[1/4,SRU,Bionic] misc: rtsx: Move Realtek Card Reader Driver to misc

Message ID 1523274968-18635-2-git-send-email-acelan.kao@canonical.com
State New
Headers show
Series
  • Add support RTS5260 card reader [10EC:5260]
Related show

Commit Message

AceLan Kao April 9, 2018, 11:56 a.m.
From: Rui Feng <rui_feng@realsil.com.cn>

BugLink: http://bugs.launchpad.net/bugs/1737673

Because Realtek card reader drivers are pcie and usb drivers,
and they bridge mmc subsystem and memstick subsystem, they are
not mfd drivers. Greg and Lee Jones had a discussion about
where to put the drivers, the result is that misc is a good
place for them, so I move all files to misc. If I don't move
them to a right place, I can't add any patch for this driver.

Signed-off-by: Rui Feng <rui_feng@realsil.com.cn>
Reviewed-by: Daniel Bristot de Oliveira <bristot@redhat.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Tested-by: Perry Yuan <perry_yuan@dell.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
(backported from commit e455b69ddf9b69326d0cab28d374faf3325489c9)
Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
---
 drivers/memstick/host/Kconfig       |    4 +-
 drivers/memstick/host/rtsx_pci_ms.c |    2 +-
 drivers/memstick/host/rtsx_usb_ms.c |    2 +-
 drivers/mfd/Kconfig                 |   21 -
 drivers/mfd/Makefile                |    4 -
 drivers/mfd/rtl8411.c               |  508 -----------
 drivers/mfd/rts5209.c               |  277 ------
 drivers/mfd/rts5227.c               |  374 ---------
 drivers/mfd/rts5229.c               |  273 ------
 drivers/mfd/rts5249.c               |  741 -----------------
 drivers/mfd/rtsx_pcr.c              | 1572 -----------------------------------
 drivers/mfd/rtsx_pcr.h              |  103 ---
 drivers/mfd/rtsx_usb.c              |  791 ------------------
 drivers/misc/Kconfig                |    5 +
 drivers/misc/Makefile               |    1 +
 drivers/misc/cardreader/Kconfig     |   20 +
 drivers/misc/cardreader/Makefile    |    4 +
 drivers/misc/cardreader/rtl8411.c   |  508 +++++++++++
 drivers/misc/cardreader/rts5209.c   |  277 ++++++
 drivers/misc/cardreader/rts5227.c   |  374 +++++++++
 drivers/misc/cardreader/rts5229.c   |  273 ++++++
 drivers/misc/cardreader/rts5249.c   |  740 +++++++++++++++++
 drivers/misc/cardreader/rtsx_pcr.c  | 1572 +++++++++++++++++++++++++++++++++++
 drivers/misc/cardreader/rtsx_pcr.h  |  103 +++
 drivers/misc/cardreader/rtsx_usb.c  |  791 ++++++++++++++++++
 drivers/mmc/host/Kconfig            |    4 +-
 drivers/mmc/host/rtsx_pci_sdmmc.c   |    2 +-
 drivers/mmc/host/rtsx_usb_sdmmc.c   |    2 +-
 include/linux/mfd/rtsx_common.h     |   50 --
 include/linux/mfd/rtsx_pci.h        | 1141 -------------------------
 include/linux/mfd/rtsx_usb.h        |  628 --------------
 include/linux/rtsx_common.h         |   50 ++
 include/linux/rtsx_pci.h            | 1141 +++++++++++++++++++++++++
 include/linux/rtsx_usb.h            |  628 ++++++++++++++
 34 files changed, 6495 insertions(+), 6491 deletions(-)
 delete mode 100644 drivers/mfd/rtl8411.c
 delete mode 100644 drivers/mfd/rts5209.c
 delete mode 100644 drivers/mfd/rts5227.c
 delete mode 100644 drivers/mfd/rts5229.c
 delete mode 100644 drivers/mfd/rts5249.c
 delete mode 100644 drivers/mfd/rtsx_pcr.c
 delete mode 100644 drivers/mfd/rtsx_pcr.h
 delete mode 100644 drivers/mfd/rtsx_usb.c
 create mode 100644 drivers/misc/cardreader/Kconfig
 create mode 100644 drivers/misc/cardreader/Makefile
 create mode 100644 drivers/misc/cardreader/rtl8411.c
 create mode 100644 drivers/misc/cardreader/rts5209.c
 create mode 100644 drivers/misc/cardreader/rts5227.c
 create mode 100644 drivers/misc/cardreader/rts5229.c
 create mode 100644 drivers/misc/cardreader/rts5249.c
 create mode 100644 drivers/misc/cardreader/rtsx_pcr.c
 create mode 100644 drivers/misc/cardreader/rtsx_pcr.h
 create mode 100644 drivers/misc/cardreader/rtsx_usb.c
 delete mode 100644 include/linux/mfd/rtsx_common.h
 delete mode 100644 include/linux/mfd/rtsx_pci.h
 delete mode 100644 include/linux/mfd/rtsx_usb.h
 create mode 100644 include/linux/rtsx_common.h
 create mode 100644 include/linux/rtsx_pci.h
 create mode 100644 include/linux/rtsx_usb.h

Patch

diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig
index 7310e32..aa2b078 100644
--- a/drivers/memstick/host/Kconfig
+++ b/drivers/memstick/host/Kconfig
@@ -45,7 +45,7 @@  config MEMSTICK_R592
 
 config MEMSTICK_REALTEK_PCI
 	tristate "Realtek PCI-E Memstick Card Interface Driver"
-	depends on MFD_RTSX_PCI
+	depends on MISC_RTSX_PCI
 	help
 	  Say Y here to include driver code to support Memstick card interface
 	  of Realtek PCI-E card reader
@@ -55,7 +55,7 @@  config MEMSTICK_REALTEK_PCI
 
 config MEMSTICK_REALTEK_USB
 	tristate "Realtek USB Memstick Card Interface Driver"
-	depends on MFD_RTSX_USB
+	depends on MISC_RTSX_USB
 	help
 	  Say Y here to include driver code to support Memstick card interface
 	  of Realtek RTS5129/39 series USB card reader
diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c
index 818fa94..a44b457 100644
--- a/drivers/memstick/host/rtsx_pci_ms.c
+++ b/drivers/memstick/host/rtsx_pci_ms.c
@@ -24,7 +24,7 @@ 
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/memstick.h>
-#include <linux/mfd/rtsx_pci.h>
+#include <linux/rtsx_pci.h>
 #include <asm/unaligned.h>
 
 struct realtek_pci_ms {
diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c
index 2e3cf01..4f64563 100644
--- a/drivers/memstick/host/rtsx_usb_ms.c
+++ b/drivers/memstick/host/rtsx_usb_ms.c
@@ -25,7 +25,7 @@ 
 #include <linux/workqueue.h>
 #include <linux/memstick.h>
 #include <linux/kthread.h>
-#include <linux/mfd/rtsx_usb.h>
+#include <linux/rtsx_usb.h>
 #include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1d20a80..1246ba1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -929,17 +929,6 @@  config MFD_RDC321X
 	  southbridge which provides access to GPIOs and Watchdog using the
 	  southbridge PCI device configuration space.
 
-config MFD_RTSX_PCI
-	tristate "Realtek PCI-E card reader"
-	depends on PCI
-	select MFD_CORE
-	help
-	  This supports for Realtek PCI-Express card reader including rts5209,
-	  rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411, etc.
-	  Realtek card reader supports access to many types of memory cards,
-	  such as Memory Stick, Memory Stick Pro, Secure Digital and
-	  MultiMediaCard.
-
 config MFD_RT5033
 	tristate "Richtek RT5033 Power Management IC"
 	depends on I2C
@@ -953,16 +942,6 @@  config MFD_RT5033
 	  sub-devices like charger, fuel gauge, flash LED, current source,
 	  LDO and Buck.
 
-config MFD_RTSX_USB
-	tristate "Realtek USB card reader"
-	depends on USB
-	select MFD_CORE
-	help
-	  Select this option to get support for Realtek USB 2.0 card readers
-	  including RTS5129, RTS5139, RTS5179 and RTS5170.
-	  Realtek card reader supports access to many types of memory cards,
-	  such as Memory Stick Pro, Secure Digital and MultiMediaCard.
-
 config MFD_RC5T583
 	bool "Ricoh RC5T583 Power Management system device"
 	depends on I2C=y
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index d9474ad..293e223 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -19,10 +19,6 @@  obj-$(CONFIG_MFD_CROS_EC_I2C)	+= cros_ec_i2c.o
 obj-$(CONFIG_MFD_CROS_EC_SPI)	+= cros_ec_spi.o
 obj-$(CONFIG_MFD_EXYNOS_LPASS)	+= exynos-lpass.o
 
-rtsx_pci-objs			:= rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
-obj-$(CONFIG_MFD_RTSX_PCI)	+= rtsx_pci.o
-obj-$(CONFIG_MFD_RTSX_USB)	+= rtsx_usb.o
-
 obj-$(CONFIG_HTC_PASIC3)	+= htc-pasic3.o
 obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 
diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c
deleted file mode 100644
index b3ae659..0000000
--- a/drivers/mfd/rtl8411.c
+++ /dev/null
@@ -1,508 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- *   Roger Tseng <rogerable@realtek.com>
- */
-
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/mfd/rtsx_pci.h>
-
-#include "rtsx_pcr.h"
-
-static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr)
-{
-	u8 val;
-
-	rtsx_pci_read_register(pcr, SYS_VER, &val);
-	return val & 0x0F;
-}
-
-static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
-{
-	u8 val = 0;
-
-	rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val);
-
-	if (val & 0x2)
-		return 1;
-	else
-		return 0;
-}
-
-static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr)
-{
-	u32 reg1 = 0;
-	u8 reg3 = 0;
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg1);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1);
-
-	if (!rtsx_vendor_setting_valid(reg1))
-		return;
-
-	pcr->aspm_en = rtsx_reg_to_aspm(reg1);
-	pcr->sd30_drive_sel_1v8 =
-		map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg1));
-	pcr->card_drive_sel &= 0x3F;
-	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1);
-
-	rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, &reg3);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3);
-	pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3);
-}
-
-static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
-{
-	u32 reg = 0;
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
-
-	if (!rtsx_vendor_setting_valid(reg))
-		return;
-
-	pcr->aspm_en = rtsx_reg_to_aspm(reg);
-	pcr->sd30_drive_sel_1v8 =
-		map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg));
-	pcr->sd30_drive_sel_3v3 =
-		map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
-}
-
-static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
-{
-	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
-}
-
-static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	rtsx_pci_init_cmd(pcr);
-
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
-			0xFF, pcr->sd30_drive_sel_3v3);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL,
-			CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
-
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	rtsx_pci_init_cmd(pcr);
-
-	if (rtl8411b_is_qfn48(pcr))
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-				CARD_PULL_CTL3, 0xFF, 0xF5);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
-			0xFF, pcr->sd30_drive_sel_3v3);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL,
-			CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, FUNC_FORCE_CTL,
-			0x06, 0x00);
-
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rtl8411_turn_on_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
-}
-
-static int rtl8411_turn_off_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01);
-}
-
-static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D);
-}
-
-static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00);
-}
-
-static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card)
-{
-	int err;
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL,
-			BPP_LDO_POWB, BPP_LDO_SUSPEND);
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	/* To avoid too large in-rush current */
-	udelay(150);
-
-	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
-			BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON);
-	if (err < 0)
-		return err;
-
-	udelay(150);
-
-	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
-			BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON);
-	if (err < 0)
-		return err;
-
-	udelay(150);
-
-	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
-			BPP_POWER_MASK, BPP_POWER_ON);
-	if (err < 0)
-		return err;
-
-	return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON);
-}
-
-static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
-{
-	int err;
-
-	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
-			BPP_POWER_MASK, BPP_POWER_OFF);
-	if (err < 0)
-		return err;
-
-	return rtsx_pci_write_register(pcr, LDO_CTL,
-			BPP_LDO_POWB, BPP_LDO_SUSPEND);
-}
-
-static int rtl8411_do_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage,
-		int bpp_tuned18_shift, int bpp_asic_1v8)
-{
-	u8 mask, val;
-	int err;
-
-	mask = (BPP_REG_TUNED18 << bpp_tuned18_shift) | BPP_PAD_MASK;
-	if (voltage == OUTPUT_3V3) {
-		err = rtsx_pci_write_register(pcr,
-				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
-		if (err < 0)
-			return err;
-		val = (BPP_ASIC_3V3 << bpp_tuned18_shift) | BPP_PAD_3V3;
-	} else if (voltage == OUTPUT_1V8) {
-		err = rtsx_pci_write_register(pcr,
-				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
-		if (err < 0)
-			return err;
-		val = (bpp_asic_1v8 << bpp_tuned18_shift) | BPP_PAD_1V8;
-	} else {
-		return -EINVAL;
-	}
-
-	return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
-}
-
-static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	return rtl8411_do_switch_output_voltage(pcr, voltage,
-			BPP_TUNED18_SHIFT_8411, BPP_ASIC_1V8);
-}
-
-static int rtl8402_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	return rtl8411_do_switch_output_voltage(pcr, voltage,
-			BPP_TUNED18_SHIFT_8402, BPP_ASIC_2V0);
-}
-
-static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
-{
-	unsigned int card_exist;
-
-	card_exist = rtsx_pci_readl(pcr, RTSX_BIPR);
-	card_exist &= CARD_EXIST;
-	if (!card_exist) {
-		/* Enable card CD */
-		rtsx_pci_write_register(pcr, CD_PAD_CTL,
-				CD_DISABLE_MASK, CD_ENABLE);
-		/* Enable card interrupt */
-		rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00);
-		return 0;
-	}
-
-	if (hweight32(card_exist) > 1) {
-		rtsx_pci_write_register(pcr, CARD_PWR_CTL,
-				BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON);
-		msleep(100);
-
-		card_exist = rtsx_pci_readl(pcr, RTSX_BIPR);
-		if (card_exist & MS_EXIST)
-			card_exist = MS_EXIST;
-		else if (card_exist & SD_EXIST)
-			card_exist = SD_EXIST;
-		else
-			card_exist = 0;
-
-		rtsx_pci_write_register(pcr, CARD_PWR_CTL,
-				BPP_POWER_MASK, BPP_POWER_OFF);
-
-		pcr_dbg(pcr, "After CD deglitch, card_exist = 0x%x\n",
-			card_exist);
-	}
-
-	if (card_exist & MS_EXIST) {
-		/* Disable SD interrupt */
-		rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40);
-		rtsx_pci_write_register(pcr, CD_PAD_CTL,
-				CD_DISABLE_MASK, MS_CD_EN_ONLY);
-	} else if (card_exist & SD_EXIST) {
-		/* Disable MS interrupt */
-		rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80);
-		rtsx_pci_write_register(pcr, CD_PAD_CTL,
-				CD_DISABLE_MASK, SD_CD_EN_ONLY);
-	}
-
-	return card_exist;
-}
-
-static int rtl8411_conv_clk_and_div_n(int input, int dir)
-{
-	int output;
-
-	if (dir == CLK_TO_DIV_N)
-		output = input * 4 / 5 - 2;
-	else
-		output = (input + 2) * 5 / 4;
-
-	return output;
-}
-
-static const struct pcr_ops rtl8411_pcr_ops = {
-	.fetch_vendor_settings = rtl8411_fetch_vendor_settings,
-	.extra_init_hw = rtl8411_extra_init_hw,
-	.optimize_phy = NULL,
-	.turn_on_led = rtl8411_turn_on_led,
-	.turn_off_led = rtl8411_turn_off_led,
-	.enable_auto_blink = rtl8411_enable_auto_blink,
-	.disable_auto_blink = rtl8411_disable_auto_blink,
-	.card_power_on = rtl8411_card_power_on,
-	.card_power_off = rtl8411_card_power_off,
-	.switch_output_voltage = rtl8411_switch_output_voltage,
-	.cd_deglitch = rtl8411_cd_deglitch,
-	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
-	.force_power_down = rtl8411_force_power_down,
-};
-
-static const struct pcr_ops rtl8402_pcr_ops = {
-	.fetch_vendor_settings = rtl8411_fetch_vendor_settings,
-	.extra_init_hw = rtl8411_extra_init_hw,
-	.optimize_phy = NULL,
-	.turn_on_led = rtl8411_turn_on_led,
-	.turn_off_led = rtl8411_turn_off_led,
-	.enable_auto_blink = rtl8411_enable_auto_blink,
-	.disable_auto_blink = rtl8411_disable_auto_blink,
-	.card_power_on = rtl8411_card_power_on,
-	.card_power_off = rtl8411_card_power_off,
-	.switch_output_voltage = rtl8402_switch_output_voltage,
-	.cd_deglitch = rtl8411_cd_deglitch,
-	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
-	.force_power_down = rtl8411_force_power_down,
-};
-
-static const struct pcr_ops rtl8411b_pcr_ops = {
-	.fetch_vendor_settings = rtl8411b_fetch_vendor_settings,
-	.extra_init_hw = rtl8411b_extra_init_hw,
-	.optimize_phy = NULL,
-	.turn_on_led = rtl8411_turn_on_led,
-	.turn_off_led = rtl8411_turn_off_led,
-	.enable_auto_blink = rtl8411_enable_auto_blink,
-	.disable_auto_blink = rtl8411_disable_auto_blink,
-	.card_power_on = rtl8411_card_power_on,
-	.card_power_off = rtl8411_card_power_off,
-	.switch_output_voltage = rtl8411_switch_output_voltage,
-	.cd_deglitch = rtl8411_cd_deglitch,
-	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
-	.force_power_down = rtl8411_force_power_down,
-};
-
-/* SD Pull Control Enable:
- *     SD_DAT[3:0] ==> pull up
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull up
- *     SD_CMD      ==> pull up
- *     SD_CLK      ==> pull down
- */
-static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
-	0,
-};
-
-/* SD Pull Control Disable:
- *     SD_DAT[3:0] ==> pull down
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull down
- *     SD_CMD      ==> pull down
- *     SD_CLK      ==> pull down
- */
-static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
-	0,
-};
-
-/* MS Pull Control Enable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
-	0,
-};
-
-/* MS Pull Control Disable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
-	0,
-};
-
-static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
-	0,
-};
-
-static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11),
-	0,
-};
-
-static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
-	0,
-};
-
-static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
-	0,
-};
-
-static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
-	0,
-};
-
-static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
-	0,
-};
-
-static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
-	0,
-};
-
-static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
-	0,
-};
-
-static void rtl8411_init_common_params(struct rtsx_pcr *pcr)
-{
-	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
-	pcr->num_slots = 2;
-	pcr->flags = 0;
-	pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT;
-	pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
-	pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
-	pcr->aspm_en = ASPM_L1_EN;
-	pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14);
-	pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10);
-	pcr->ic_version = rtl8411_get_ic_version(pcr);
-}
-
-void rtl8411_init_params(struct rtsx_pcr *pcr)
-{
-	rtl8411_init_common_params(pcr);
-	pcr->ops = &rtl8411_pcr_ops;
-	set_pull_ctrl_tables(pcr, rtl8411);
-}
-
-void rtl8411b_init_params(struct rtsx_pcr *pcr)
-{
-	rtl8411_init_common_params(pcr);
-	pcr->ops = &rtl8411b_pcr_ops;
-	if (rtl8411b_is_qfn48(pcr))
-		set_pull_ctrl_tables(pcr, rtl8411b_qfn48);
-	else
-		set_pull_ctrl_tables(pcr, rtl8411b_qfn64);
-}
-
-void rtl8402_init_params(struct rtsx_pcr *pcr)
-{
-	rtl8411_init_common_params(pcr);
-	pcr->ops = &rtl8402_pcr_ops;
-	set_pull_ctrl_tables(pcr, rtl8411);
-}
diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c
deleted file mode 100644
index b95beec..0000000
--- a/drivers/mfd/rts5209.c
+++ /dev/null
@@ -1,277 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mfd/rtsx_pci.h>
-
-#include "rtsx_pcr.h"
-
-static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr)
-{
-	u8 val;
-
-	val = rtsx_pci_readb(pcr, 0x1C);
-	return val & 0x0F;
-}
-
-static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
-{
-	u32 reg;
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
-
-	if (rts5209_vendor_setting1_valid(reg)) {
-		if (rts5209_reg_check_ms_pmos(reg))
-			pcr->flags |= PCR_MS_PMOS;
-		pcr->aspm_en = rts5209_reg_to_aspm(reg);
-	}
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
-
-	if (rts5209_vendor_setting2_valid(reg)) {
-		pcr->sd30_drive_sel_1v8 =
-			rts5209_reg_to_sd30_drive_sel_1v8(reg);
-		pcr->sd30_drive_sel_3v3 =
-			rts5209_reg_to_sd30_drive_sel_3v3(reg);
-		pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg);
-	}
-}
-
-static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
-{
-	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
-}
-
-static int rts5209_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	rtsx_pci_init_cmd(pcr);
-
-	/* Turn off LED */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03);
-	/* Reset ASPM state to default value */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
-	/* Force CLKREQ# PIN to drive 0 to request clock */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
-	/* Configure GPIO as output */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03);
-	/* Configure driving */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
-			0xFF, pcr->sd30_drive_sel_3v3);
-
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5209_optimize_phy(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966);
-}
-
-static int rts5209_turn_on_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
-}
-
-static int rts5209_turn_off_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01);
-}
-
-static int rts5209_enable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D);
-}
-
-static int rts5209_disable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00);
-}
-
-static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card)
-{
-	int err;
-	u8 pwr_mask, partial_pwr_on, pwr_on;
-
-	pwr_mask = SD_POWER_MASK;
-	partial_pwr_on = SD_PARTIAL_POWER_ON;
-	pwr_on = SD_POWER_ON;
-
-	if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
-		pwr_mask = MS_POWER_MASK;
-		partial_pwr_on = MS_PARTIAL_POWER_ON;
-		pwr_on = MS_POWER_ON;
-	}
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			pwr_mask, partial_pwr_on);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x04);
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	/* To avoid too large in-rush current */
-	udelay(150);
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x00);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card)
-{
-	u8 pwr_mask, pwr_off;
-
-	pwr_mask = SD_POWER_MASK;
-	pwr_off = SD_POWER_OFF;
-
-	if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
-		pwr_mask = MS_POWER_MASK;
-		pwr_off = MS_POWER_OFF;
-	}
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x06);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	int err;
-
-	if (voltage == OUTPUT_3V3) {
-		err = rtsx_pci_write_register(pcr,
-				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
-		if (err < 0)
-			return err;
-		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
-		if (err < 0)
-			return err;
-	} else if (voltage == OUTPUT_1V8) {
-		err = rtsx_pci_write_register(pcr,
-				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
-		if (err < 0)
-			return err;
-		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
-		if (err < 0)
-			return err;
-	} else {
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static const struct pcr_ops rts5209_pcr_ops = {
-	.fetch_vendor_settings = rts5209_fetch_vendor_settings,
-	.extra_init_hw = rts5209_extra_init_hw,
-	.optimize_phy = rts5209_optimize_phy,
-	.turn_on_led = rts5209_turn_on_led,
-	.turn_off_led = rts5209_turn_off_led,
-	.enable_auto_blink = rts5209_enable_auto_blink,
-	.disable_auto_blink = rts5209_disable_auto_blink,
-	.card_power_on = rts5209_card_power_on,
-	.card_power_off = rts5209_card_power_off,
-	.switch_output_voltage = rts5209_switch_output_voltage,
-	.cd_deglitch = NULL,
-	.conv_clk_and_div_n = NULL,
-	.force_power_down = rts5209_force_power_down,
-};
-
-/* SD Pull Control Enable:
- *     SD_DAT[3:0] ==> pull up
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull up
- *     SD_CMD      ==> pull up
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5209_sd_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
-	0,
-};
-
-/* SD Pull Control Disable:
- *     SD_DAT[3:0] ==> pull down
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull down
- *     SD_CMD      ==> pull down
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5209_sd_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
-	0,
-};
-
-/* MS Pull Control Enable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5209_ms_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-/* MS Pull Control Disable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5209_ms_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-void rts5209_init_params(struct rtsx_pcr *pcr)
-{
-	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 |
-		EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT;
-	pcr->num_slots = 2;
-	pcr->ops = &rts5209_pcr_ops;
-
-	pcr->flags = 0;
-	pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT;
-	pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
-	pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
-	pcr->aspm_en = ASPM_L1_EN;
-	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16);
-	pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
-
-	pcr->ic_version = rts5209_get_ic_version(pcr);
-	pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl;
-	pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl;
-	pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl;
-	pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl;
-}
diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c
deleted file mode 100644
index ff296a4..0000000
--- a/drivers/mfd/rts5227.c
+++ /dev/null
@@ -1,374 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- *   Roger Tseng <rogerable@realtek.com>
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mfd/rtsx_pci.h>
-
-#include "rtsx_pcr.h"
-
-static u8 rts5227_get_ic_version(struct rtsx_pcr *pcr)
-{
-	u8 val;
-
-	rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
-	return val & 0x0F;
-}
-
-static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
-{
-	u8 driving_3v3[4][3] = {
-		{0x13, 0x13, 0x13},
-		{0x96, 0x96, 0x96},
-		{0x7F, 0x7F, 0x7F},
-		{0x96, 0x96, 0x96},
-	};
-	u8 driving_1v8[4][3] = {
-		{0x99, 0x99, 0x99},
-		{0xAA, 0xAA, 0xAA},
-		{0xFE, 0xFE, 0xFE},
-		{0xB3, 0xB3, 0xB3},
-	};
-	u8 (*driving)[3], drive_sel;
-
-	if (voltage == OUTPUT_3V3) {
-		driving = driving_3v3;
-		drive_sel = pcr->sd30_drive_sel_3v3;
-	} else {
-		driving = driving_1v8;
-		drive_sel = pcr->sd30_drive_sel_1v8;
-	}
-
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
-			0xFF, driving[drive_sel][0]);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
-			0xFF, driving[drive_sel][1]);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
-			0xFF, driving[drive_sel][2]);
-}
-
-static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
-{
-	u32 reg;
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
-
-	if (!rtsx_vendor_setting_valid(reg))
-		return;
-
-	pcr->aspm_en = rtsx_reg_to_aspm(reg);
-	pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
-	pcr->card_drive_sel &= 0x3F;
-	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
-	pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
-	if (rtsx_reg_check_reverse_socket(reg))
-		pcr->flags |= PCR_REVERSE_SOCKET;
-}
-
-static void rts5227_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
-{
-	/* Set relink_time to 0 */
-	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0);
-	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0);
-	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0);
-
-	if (pm_state == HOST_ENTER_S3)
-		rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x10);
-
-	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
-}
-
-static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	u16 cap;
-
-	rtsx_pci_init_cmd(pcr);
-
-	/* Configure GPIO as output */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
-	/* Reset ASPM state to default value */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
-	/* Switch LDO3318 source from DV33 to card_3v3 */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
-	/* LED shine disabled, set initial shine cycle period */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
-	/* Configure LTR */
-	pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cap);
-	if (cap & PCI_EXP_DEVCTL2_LTR_EN)
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3);
-	/* Configure OBFF */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03);
-	/* Configure driving */
-	rts5227_fill_driving(pcr, OUTPUT_3V3);
-	/* Configure force_clock_req */
-	if (pcr->flags & PCR_REVERSE_SOCKET)
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0xB8);
-	else
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0x88);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, pcr->reg_pm_ctrl3, 0x10, 0x00);
-
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
-{
-	int err;
-
-	err = rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00);
-	if (err < 0)
-		return err;
-
-	/* Optimize RX sensitivity */
-	return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
-}
-
-static int rts5227_turn_on_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
-}
-
-static int rts5227_turn_off_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
-}
-
-static int rts5227_enable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
-}
-
-static int rts5227_disable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
-}
-
-static int rts5227_card_power_on(struct rtsx_pcr *pcr, int card)
-{
-	int err;
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK, SD_PARTIAL_POWER_ON);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x02);
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	/* To avoid too large in-rush current */
-	udelay(150);
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK, SD_POWER_ON);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x06);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card)
-{
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK | PMOS_STRG_MASK,
-			SD_POWER_OFF | PMOS_STRG_400mA);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0X00);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	int err;
-
-	if (voltage == OUTPUT_3V3) {
-		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
-		if (err < 0)
-			return err;
-	} else if (voltage == OUTPUT_1V8) {
-		err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02);
-		if (err < 0)
-			return err;
-		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24);
-		if (err < 0)
-			return err;
-	} else {
-		return -EINVAL;
-	}
-
-	/* set pad drive */
-	rtsx_pci_init_cmd(pcr);
-	rts5227_fill_driving(pcr, voltage);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static const struct pcr_ops rts5227_pcr_ops = {
-	.fetch_vendor_settings = rts5227_fetch_vendor_settings,
-	.extra_init_hw = rts5227_extra_init_hw,
-	.optimize_phy = rts5227_optimize_phy,
-	.turn_on_led = rts5227_turn_on_led,
-	.turn_off_led = rts5227_turn_off_led,
-	.enable_auto_blink = rts5227_enable_auto_blink,
-	.disable_auto_blink = rts5227_disable_auto_blink,
-	.card_power_on = rts5227_card_power_on,
-	.card_power_off = rts5227_card_power_off,
-	.switch_output_voltage = rts5227_switch_output_voltage,
-	.cd_deglitch = NULL,
-	.conv_clk_and_div_n = NULL,
-	.force_power_down = rts5227_force_power_down,
-};
-
-/* SD Pull Control Enable:
- *     SD_DAT[3:0] ==> pull up
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull up
- *     SD_CMD      ==> pull up
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5227_sd_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
-	0,
-};
-
-/* SD Pull Control Disable:
- *     SD_DAT[3:0] ==> pull down
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull down
- *     SD_CMD      ==> pull down
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5227_sd_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
-	0,
-};
-
-/* MS Pull Control Enable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5227_ms_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-/* MS Pull Control Disable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5227_ms_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-void rts5227_init_params(struct rtsx_pcr *pcr)
-{
-	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
-	pcr->num_slots = 2;
-	pcr->ops = &rts5227_pcr_ops;
-
-	pcr->flags = 0;
-	pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
-	pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
-	pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
-	pcr->aspm_en = ASPM_L1_EN;
-	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15);
-	pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 7, 7);
-
-	pcr->ic_version = rts5227_get_ic_version(pcr);
-	pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl;
-	pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl;
-	pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl;
-	pcr->ms_pull_ctl_disable_tbl = rts5227_ms_pull_ctl_disable_tbl;
-
-	pcr->reg_pm_ctrl3 = PM_CTRL3;
-}
-
-static int rts522a_optimize_phy(struct rtsx_pcr *pcr)
-{
-	int err;
-
-	err = rtsx_pci_write_register(pcr, RTS522A_PM_CTRL3, D3_DELINK_MODE_EN,
-		0x00);
-	if (err < 0)
-		return err;
-
-	if (is_version(pcr, 0x522A, IC_VER_A)) {
-		err = rtsx_pci_write_phy_register(pcr, PHY_RCR2,
-			PHY_RCR2_INIT_27S);
-		if (err)
-			return err;
-
-		rtsx_pci_write_phy_register(pcr, PHY_RCR1, PHY_RCR1_INIT_27S);
-		rtsx_pci_write_phy_register(pcr, PHY_FLD0, PHY_FLD0_INIT_27S);
-		rtsx_pci_write_phy_register(pcr, PHY_FLD3, PHY_FLD3_INIT_27S);
-		rtsx_pci_write_phy_register(pcr, PHY_FLD4, PHY_FLD4_INIT_27S);
-	}
-
-	return 0;
-}
-
-static int rts522a_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	rts5227_extra_init_hw(pcr);
-
-	rtsx_pci_write_register(pcr, FUNC_FORCE_CTL, FUNC_FORCE_UPME_XMT_DBG,
-		FUNC_FORCE_UPME_XMT_DBG);
-	rtsx_pci_write_register(pcr, PCLK_CTL, 0x04, 0x04);
-	rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0);
-	rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 0xFF, 0x11);
-
-	return 0;
-}
-
-/* rts522a operations mainly derived from rts5227, except phy/hw init setting.
- */
-static const struct pcr_ops rts522a_pcr_ops = {
-	.fetch_vendor_settings = rts5227_fetch_vendor_settings,
-	.extra_init_hw = rts522a_extra_init_hw,
-	.optimize_phy = rts522a_optimize_phy,
-	.turn_on_led = rts5227_turn_on_led,
-	.turn_off_led = rts5227_turn_off_led,
-	.enable_auto_blink = rts5227_enable_auto_blink,
-	.disable_auto_blink = rts5227_disable_auto_blink,
-	.card_power_on = rts5227_card_power_on,
-	.card_power_off = rts5227_card_power_off,
-	.switch_output_voltage = rts5227_switch_output_voltage,
-	.cd_deglitch = NULL,
-	.conv_clk_and_div_n = NULL,
-	.force_power_down = rts5227_force_power_down,
-};
-
-void rts522a_init_params(struct rtsx_pcr *pcr)
-{
-	rts5227_init_params(pcr);
-
-	pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
-}
diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c
deleted file mode 100644
index 9ed9dc8..0000000
--- a/drivers/mfd/rts5229.c
+++ /dev/null
@@ -1,273 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mfd/rtsx_pci.h>
-
-#include "rtsx_pcr.h"
-
-static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr)
-{
-	u8 val;
-
-	rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
-	return val & 0x0F;
-}
-
-static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
-{
-	u32 reg;
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
-
-	if (!rtsx_vendor_setting_valid(reg))
-		return;
-
-	pcr->aspm_en = rtsx_reg_to_aspm(reg);
-	pcr->sd30_drive_sel_1v8 =
-		map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg));
-	pcr->card_drive_sel &= 0x3F;
-	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
-	pcr->sd30_drive_sel_3v3 =
-		map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
-}
-
-static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
-{
-	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
-}
-
-static int rts5229_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	rtsx_pci_init_cmd(pcr);
-
-	/* Configure GPIO as output */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
-	/* Reset ASPM state to default value */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
-	/* Force CLKREQ# PIN to drive 0 to request clock */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
-	/* Switch LDO3318 source from DV33 to card_3v3 */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
-	/* LED shine disabled, set initial shine cycle period */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
-	/* Configure driving */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
-			0xFF, pcr->sd30_drive_sel_3v3);
-
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5229_optimize_phy(struct rtsx_pcr *pcr)
-{
-	/* Optimize RX sensitivity */
-	return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
-}
-
-static int rts5229_turn_on_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
-}
-
-static int rts5229_turn_off_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
-}
-
-static int rts5229_enable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
-}
-
-static int rts5229_disable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
-}
-
-static int rts5229_card_power_on(struct rtsx_pcr *pcr, int card)
-{
-	int err;
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK, SD_PARTIAL_POWER_ON);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x02);
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	/* To avoid too large in-rush current */
-	udelay(150);
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK, SD_POWER_ON);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x06);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card)
-{
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK | PMOS_STRG_MASK,
-			SD_POWER_OFF | PMOS_STRG_400mA);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x00);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	int err;
-
-	if (voltage == OUTPUT_3V3) {
-		err = rtsx_pci_write_register(pcr,
-				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
-		if (err < 0)
-			return err;
-		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
-		if (err < 0)
-			return err;
-	} else if (voltage == OUTPUT_1V8) {
-		err = rtsx_pci_write_register(pcr,
-				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
-		if (err < 0)
-			return err;
-		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
-		if (err < 0)
-			return err;
-	} else {
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static const struct pcr_ops rts5229_pcr_ops = {
-	.fetch_vendor_settings = rts5229_fetch_vendor_settings,
-	.extra_init_hw = rts5229_extra_init_hw,
-	.optimize_phy = rts5229_optimize_phy,
-	.turn_on_led = rts5229_turn_on_led,
-	.turn_off_led = rts5229_turn_off_led,
-	.enable_auto_blink = rts5229_enable_auto_blink,
-	.disable_auto_blink = rts5229_disable_auto_blink,
-	.card_power_on = rts5229_card_power_on,
-	.card_power_off = rts5229_card_power_off,
-	.switch_output_voltage = rts5229_switch_output_voltage,
-	.cd_deglitch = NULL,
-	.conv_clk_and_div_n = NULL,
-	.force_power_down = rts5229_force_power_down,
-};
-
-/* SD Pull Control Enable:
- *     SD_DAT[3:0] ==> pull up
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull up
- *     SD_CMD      ==> pull up
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5229_sd_pull_ctl_enable_tbl1[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
-	0,
-};
-
-/* For RTS5229 version C */
-static const u32 rts5229_sd_pull_ctl_enable_tbl2[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9),
-	0,
-};
-
-/* SD Pull Control Disable:
- *     SD_DAT[3:0] ==> pull down
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull down
- *     SD_CMD      ==> pull down
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5229_sd_pull_ctl_disable_tbl1[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
-	0,
-};
-
-/* For RTS5229 version C */
-static const u32 rts5229_sd_pull_ctl_disable_tbl2[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5),
-	0,
-};
-
-/* MS Pull Control Enable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5229_ms_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-/* MS Pull Control Disable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5229_ms_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-void rts5229_init_params(struct rtsx_pcr *pcr)
-{
-	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
-	pcr->num_slots = 2;
-	pcr->ops = &rts5229_pcr_ops;
-
-	pcr->flags = 0;
-	pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
-	pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
-	pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
-	pcr->aspm_en = ASPM_L1_EN;
-	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15);
-	pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6);
-
-	pcr->ic_version = rts5229_get_ic_version(pcr);
-	if (pcr->ic_version == IC_VER_C) {
-		pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2;
-		pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2;
-	} else {
-		pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1;
-		pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1;
-	}
-	pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl;
-	pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl;
-}
diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c
deleted file mode 100644
index 7fcf37b..0000000
--- a/drivers/mfd/rts5249.c
+++ /dev/null
@@ -1,741 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/mfd/rtsx_pci.h>
-
-#include "rtsx_pcr.h"
-
-static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr)
-{
-	u8 val;
-
-	rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
-	return val & 0x0F;
-}
-
-static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
-{
-	u8 driving_3v3[4][3] = {
-		{0x11, 0x11, 0x18},
-		{0x55, 0x55, 0x5C},
-		{0xFF, 0xFF, 0xFF},
-		{0x96, 0x96, 0x96},
-	};
-	u8 driving_1v8[4][3] = {
-		{0xC4, 0xC4, 0xC4},
-		{0x3C, 0x3C, 0x3C},
-		{0xFE, 0xFE, 0xFE},
-		{0xB3, 0xB3, 0xB3},
-	};
-	u8 (*driving)[3], drive_sel;
-
-	if (voltage == OUTPUT_3V3) {
-		driving = driving_3v3;
-		drive_sel = pcr->sd30_drive_sel_3v3;
-	} else {
-		driving = driving_1v8;
-		drive_sel = pcr->sd30_drive_sel_1v8;
-	}
-
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
-			0xFF, driving[drive_sel][0]);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
-			0xFF, driving[drive_sel][1]);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
-			0xFF, driving[drive_sel][2]);
-}
-
-static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
-{
-	u32 reg;
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
-
-	if (!rtsx_vendor_setting_valid(reg)) {
-		pcr_dbg(pcr, "skip fetch vendor setting\n");
-		return;
-	}
-
-	pcr->aspm_en = rtsx_reg_to_aspm(reg);
-	pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
-	pcr->card_drive_sel &= 0x3F;
-	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
-
-	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
-	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
-	pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
-	if (rtsx_reg_check_reverse_socket(reg))
-		pcr->flags |= PCR_REVERSE_SOCKET;
-}
-
-static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
-{
-	/* Set relink_time to 0 */
-	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0);
-	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0);
-	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0);
-
-	if (pm_state == HOST_ENTER_S3)
-		rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
-			D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
-
-	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
-}
-
-static void rts5249_init_from_cfg(struct rtsx_pcr *pcr)
-{
-	struct rtsx_cr_option *option = &(pcr->option);
-	u32 lval;
-
-	if (CHK_PCI_PID(pcr, PID_524A))
-		rtsx_pci_read_config_dword(pcr,
-			PCR_ASPM_SETTING_REG1, &lval);
-	else
-		rtsx_pci_read_config_dword(pcr,
-			PCR_ASPM_SETTING_REG2, &lval);
-
-	if (lval & ASPM_L1_1_EN_MASK)
-		rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
-
-	if (lval & ASPM_L1_2_EN_MASK)
-		rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
-
-	if (lval & PM_L1_1_EN_MASK)
-		rtsx_set_dev_flag(pcr, PM_L1_1_EN);
-
-	if (lval & PM_L1_2_EN_MASK)
-		rtsx_set_dev_flag(pcr, PM_L1_2_EN);
-
-	if (option->ltr_en) {
-		u16 val;
-
-		pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
-		if (val & PCI_EXP_DEVCTL2_LTR_EN) {
-			option->ltr_enabled = true;
-			option->ltr_active = true;
-			rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
-		} else {
-			option->ltr_enabled = false;
-		}
-	}
-}
-
-static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
-{
-	struct rtsx_cr_option *option = &(pcr->option);
-
-	if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
-				| PM_L1_1_EN | PM_L1_2_EN))
-		option->force_clkreq_0 = false;
-	else
-		option->force_clkreq_0 = true;
-
-	return 0;
-}
-
-static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	struct rtsx_cr_option *option = &(pcr->option);
-
-	rts5249_init_from_cfg(pcr);
-	rts5249_init_from_hw(pcr);
-
-	rtsx_pci_init_cmd(pcr);
-
-	/* Rest L1SUB Config */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, L1SUB_CONFIG3, 0xFF, 0x00);
-	/* Configure GPIO as output */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
-	/* Reset ASPM state to default value */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
-	/* Switch LDO3318 source from DV33 to card_3v3 */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
-	/* LED shine disabled, set initial shine cycle period */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
-	/* Configure driving */
-	rts5249_fill_driving(pcr, OUTPUT_3V3);
-	if (pcr->flags & PCR_REVERSE_SOCKET)
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0xB0);
-	else
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80);
-
-	/*
-	 * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
-	 * to drive low, and we forcibly request clock.
-	 */
-	if (option->force_clkreq_0)
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
-			FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
-	else
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
-			FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
-
-	return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
-}
-
-static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
-{
-	int err;
-
-	err = rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00);
-	if (err < 0)
-		return err;
-
-	err = rtsx_pci_write_phy_register(pcr, PHY_REV,
-			PHY_REV_RESV | PHY_REV_RXIDLE_LATCHED |
-			PHY_REV_P1_EN | PHY_REV_RXIDLE_EN |
-			PHY_REV_CLKREQ_TX_EN | PHY_REV_RX_PWST |
-			PHY_REV_CLKREQ_DT_1_0 | PHY_REV_STOP_CLKRD |
-			PHY_REV_STOP_CLKWR);
-	if (err < 0)
-		return err;
-
-	msleep(1);
-
-	err = rtsx_pci_write_phy_register(pcr, PHY_BPCR,
-			PHY_BPCR_IBRXSEL | PHY_BPCR_IBTXSEL |
-			PHY_BPCR_IB_FILTER | PHY_BPCR_CMIRROR_EN);
-	if (err < 0)
-		return err;
-
-	err = rtsx_pci_write_phy_register(pcr, PHY_PCR,
-			PHY_PCR_FORCE_CODE | PHY_PCR_OOBS_CALI_50 |
-			PHY_PCR_OOBS_VCM_08 | PHY_PCR_OOBS_SEN_90 |
-			PHY_PCR_RSSI_EN | PHY_PCR_RX10K);
-	if (err < 0)
-		return err;
-
-	err = rtsx_pci_write_phy_register(pcr, PHY_RCR2,
-			PHY_RCR2_EMPHASE_EN | PHY_RCR2_NADJR |
-			PHY_RCR2_CDR_SR_2 | PHY_RCR2_FREQSEL_12 |
-			PHY_RCR2_CDR_SC_12P | PHY_RCR2_CALIB_LATE);
-	if (err < 0)
-		return err;
-
-	err = rtsx_pci_write_phy_register(pcr, PHY_FLD4,
-			PHY_FLD4_FLDEN_SEL | PHY_FLD4_REQ_REF |
-			PHY_FLD4_RXAMP_OFF | PHY_FLD4_REQ_ADDA |
-			PHY_FLD4_BER_COUNT | PHY_FLD4_BER_TIMER |
-			PHY_FLD4_BER_CHK_EN);
-	if (err < 0)
-		return err;
-	err = rtsx_pci_write_phy_register(pcr, PHY_RDR,
-			PHY_RDR_RXDSEL_1_9 | PHY_SSC_AUTO_PWD);
-	if (err < 0)
-		return err;
-	err = rtsx_pci_write_phy_register(pcr, PHY_RCR1,
-			PHY_RCR1_ADP_TIME_4 | PHY_RCR1_VCO_COARSE);
-	if (err < 0)
-		return err;
-	err = rtsx_pci_write_phy_register(pcr, PHY_FLD3,
-			PHY_FLD3_TIMER_4 | PHY_FLD3_TIMER_6 |
-			PHY_FLD3_RXDELINK);
-	if (err < 0)
-		return err;
-
-	return rtsx_pci_write_phy_register(pcr, PHY_TUNE,
-			PHY_TUNE_TUNEREF_1_0 | PHY_TUNE_VBGSEL_1252 |
-			PHY_TUNE_SDBUS_33 | PHY_TUNE_TUNED18 |
-			PHY_TUNE_TUNED12 | PHY_TUNE_TUNEA12);
-}
-
-static int rtsx_base_turn_on_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
-}
-
-static int rtsx_base_turn_off_led(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
-}
-
-static int rtsx_base_enable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
-}
-
-static int rtsx_base_disable_auto_blink(struct rtsx_pcr *pcr)
-{
-	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
-}
-
-static int rtsx_base_card_power_on(struct rtsx_pcr *pcr, int card)
-{
-	int err;
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x02);
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	msleep(5);
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK, SD_VCC_POWER_ON);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x06);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rtsx_base_card_power_off(struct rtsx_pcr *pcr, int card)
-{
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
-			SD_POWER_MASK, SD_POWER_OFF);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-			LDO3318_PWR_MASK, 0x00);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rtsx_base_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	int err;
-	u16 append;
-
-	switch (voltage) {
-	case OUTPUT_3V3:
-		err = rtsx_pci_update_phy(pcr, PHY_TUNE, PHY_TUNE_VOLTAGE_MASK,
-			PHY_TUNE_VOLTAGE_3V3);
-		if (err < 0)
-			return err;
-		break;
-	case OUTPUT_1V8:
-		append = PHY_TUNE_D18_1V8;
-		if (CHK_PCI_PID(pcr, 0x5249)) {
-			err = rtsx_pci_update_phy(pcr, PHY_BACR,
-				PHY_BACR_BASIC_MASK, 0);
-			if (err < 0)
-				return err;
-			append = PHY_TUNE_D18_1V7;
-		}
-
-		err = rtsx_pci_update_phy(pcr, PHY_TUNE, PHY_TUNE_VOLTAGE_MASK,
-			append);
-		if (err < 0)
-			return err;
-		break;
-	default:
-		pcr_dbg(pcr, "unknown output voltage %d\n", voltage);
-		return -EINVAL;
-	}
-
-	/* set pad drive */
-	rtsx_pci_init_cmd(pcr);
-	rts5249_fill_driving(pcr, voltage);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static void rts5249_set_aspm(struct rtsx_pcr *pcr, bool enable)
-{
-	struct rtsx_cr_option *option = &pcr->option;
-	u8 val = 0;
-
-	if (pcr->aspm_enabled == enable)
-		return;
-
-	if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
-		if (enable)
-			val = pcr->aspm_en;
-		rtsx_pci_update_cfg_byte(pcr,
-			pcr->pcie_cap + PCI_EXP_LNKCTL,
-			ASPM_MASK_NEG, val);
-	} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
-		u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0;
-
-		if (!enable)
-			val = FORCE_ASPM_CTL0;
-		rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
-	}
-
-	pcr->aspm_enabled = enable;
-}
-
-static const struct pcr_ops rts5249_pcr_ops = {
-	.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
-	.extra_init_hw = rts5249_extra_init_hw,
-	.optimize_phy = rts5249_optimize_phy,
-	.turn_on_led = rtsx_base_turn_on_led,
-	.turn_off_led = rtsx_base_turn_off_led,
-	.enable_auto_blink = rtsx_base_enable_auto_blink,
-	.disable_auto_blink = rtsx_base_disable_auto_blink,
-	.card_power_on = rtsx_base_card_power_on,
-	.card_power_off = rtsx_base_card_power_off,
-	.switch_output_voltage = rtsx_base_switch_output_voltage,
-	.force_power_down = rtsx_base_force_power_down,
-	.set_aspm = rts5249_set_aspm,
-};
-
-/* SD Pull Control Enable:
- *     SD_DAT[3:0] ==> pull up
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull up
- *     SD_CMD      ==> pull up
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5249_sd_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA),
-	0,
-};
-
-/* SD Pull Control Disable:
- *     SD_DAT[3:0] ==> pull down
- *     SD_CD       ==> pull up
- *     SD_WP       ==> pull down
- *     SD_CMD      ==> pull down
- *     SD_CLK      ==> pull down
- */
-static const u32 rts5249_sd_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
-	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
-	0,
-};
-
-/* MS Pull Control Enable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5249_ms_pull_ctl_enable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-/* MS Pull Control Disable:
- *     MS CD       ==> pull up
- *     others      ==> pull down
- */
-static const u32 rts5249_ms_pull_ctl_disable_tbl[] = {
-	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
-	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
-	0,
-};
-
-void rts5249_init_params(struct rtsx_pcr *pcr)
-{
-	struct rtsx_cr_option *option = &(pcr->option);
-
-	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
-	pcr->num_slots = 2;
-	pcr->ops = &rts5249_pcr_ops;
-
-	pcr->flags = 0;
-	pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
-	pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
-	pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
-	pcr->aspm_en = ASPM_L1_EN;
-	pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
-	pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
-
-	pcr->ic_version = rts5249_get_ic_version(pcr);
-	pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl;
-	pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl;
-	pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl;
-	pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl;
-
-	pcr->reg_pm_ctrl3 = PM_CTRL3;
-
-	option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
-				| LTR_L1SS_PWR_GATE_EN);
-	option->ltr_en = true;
-
-	/* Init latency of active, idle, L1OFF to 60us, 300us, 3ms */
-	option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
-	option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
-	option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
-	option->dev_aspm_mode = DEV_ASPM_DYNAMIC;
-	option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
-	option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5249_DEF;
-	option->ltr_l1off_snooze_sspwrgate =
-		LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF;
-}
-
-static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val)
-{
-	addr = addr & 0x80 ? (addr & 0x7F) | 0x40 : addr;
-
-	return __rtsx_pci_write_phy_register(pcr, addr, val);
-}
-
-static int rts524a_read_phy(struct rtsx_pcr *pcr, u8 addr, u16 *val)
-{
-	addr = addr & 0x80 ? (addr & 0x7F) | 0x40 : addr;
-
-	return __rtsx_pci_read_phy_register(pcr, addr, val);
-}
-
-static int rts524a_optimize_phy(struct rtsx_pcr *pcr)
-{
-	int err;
-
-	err = rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
-		D3_DELINK_MODE_EN, 0x00);
-	if (err < 0)
-		return err;
-
-	rtsx_pci_write_phy_register(pcr, PHY_PCR,
-		PHY_PCR_FORCE_CODE | PHY_PCR_OOBS_CALI_50 |
-		PHY_PCR_OOBS_VCM_08 | PHY_PCR_OOBS_SEN_90 | PHY_PCR_RSSI_EN);
-	rtsx_pci_write_phy_register(pcr, PHY_SSCCR3,
-		PHY_SSCCR3_STEP_IN | PHY_SSCCR3_CHECK_DELAY);
-
-	if (is_version(pcr, 0x524A, IC_VER_A)) {
-		rtsx_pci_write_phy_register(pcr, PHY_SSCCR3,
-			PHY_SSCCR3_STEP_IN | PHY_SSCCR3_CHECK_DELAY);
-		rtsx_pci_write_phy_register(pcr, PHY_SSCCR2,
-			PHY_SSCCR2_PLL_NCODE | PHY_SSCCR2_TIME0 |
-			PHY_SSCCR2_TIME2_WIDTH);
-		rtsx_pci_write_phy_register(pcr, PHY_ANA1A,
-			PHY_ANA1A_TXR_LOOPBACK | PHY_ANA1A_RXT_BIST |
-			PHY_ANA1A_TXR_BIST | PHY_ANA1A_REV);
-		rtsx_pci_write_phy_register(pcr, PHY_ANA1D,
-			PHY_ANA1D_DEBUG_ADDR);
-		rtsx_pci_write_phy_register(pcr, PHY_DIG1E,
-			PHY_DIG1E_REV | PHY_DIG1E_D0_X_D1 |
-			PHY_DIG1E_RX_ON_HOST | PHY_DIG1E_RCLK_REF_HOST |
-			PHY_DIG1E_RCLK_TX_EN_KEEP |
-			PHY_DIG1E_RCLK_TX_TERM_KEEP |
-			PHY_DIG1E_RCLK_RX_EIDLE_ON | PHY_DIG1E_TX_TERM_KEEP |
-			PHY_DIG1E_RX_TERM_KEEP | PHY_DIG1E_TX_EN_KEEP |
-			PHY_DIG1E_RX_EN_KEEP);
-	}
-
-	rtsx_pci_write_phy_register(pcr, PHY_ANA08,
-		PHY_ANA08_RX_EQ_DCGAIN | PHY_ANA08_SEL_RX_EN |
-		PHY_ANA08_RX_EQ_VAL | PHY_ANA08_SCP | PHY_ANA08_SEL_IPI);
-
-	return 0;
-}
-
-static int rts524a_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	rts5249_extra_init_hw(pcr);
-
-	rtsx_pci_write_register(pcr, FUNC_FORCE_CTL,
-		FORCE_ASPM_L1_EN, FORCE_ASPM_L1_EN);
-	rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0);
-	rtsx_pci_write_register(pcr, LDO_VCC_CFG1, LDO_VCC_LMT_EN,
-		LDO_VCC_LMT_EN);
-	rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL);
-	if (is_version(pcr, 0x524A, IC_VER_A)) {
-		rtsx_pci_write_register(pcr, LDO_DV18_CFG,
-			LDO_DV18_SR_MASK, LDO_DV18_SR_DF);
-		rtsx_pci_write_register(pcr, LDO_VCC_CFG1,
-			LDO_VCC_REF_TUNE_MASK, LDO_VCC_REF_1V2);
-		rtsx_pci_write_register(pcr, LDO_VIO_CFG,
-			LDO_VIO_REF_TUNE_MASK, LDO_VIO_REF_1V2);
-		rtsx_pci_write_register(pcr, LDO_VIO_CFG,
-			LDO_VIO_SR_MASK, LDO_VIO_SR_DF);
-		rtsx_pci_write_register(pcr, LDO_DV12S_CFG,
-			LDO_REF12_TUNE_MASK, LDO_REF12_TUNE_DF);
-		rtsx_pci_write_register(pcr, SD40_LDO_CTL1,
-			SD40_VIO_TUNE_MASK, SD40_VIO_TUNE_1V7);
-	}
-
-	return 0;
-}
-
-static void rts5250_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
-{
-	struct rtsx_cr_option *option = &(pcr->option);
-
-	u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR);
-	int card_exist = (interrupt & SD_EXIST) | (interrupt & MS_EXIST);
-	int aspm_L1_1, aspm_L1_2;
-	u8 val = 0;
-
-	aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
-	aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
-
-	if (active) {
-		/* Run, latency: 60us */
-		if (aspm_L1_1)
-			val = option->ltr_l1off_snooze_sspwrgate;
-	} else {
-		/* L1off, latency: 300us */
-		if (aspm_L1_2)
-			val = option->ltr_l1off_sspwrgate;
-	}
-
-	if (aspm_L1_1 || aspm_L1_2) {
-		if (rtsx_check_dev_flag(pcr,
-					LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) {
-			if (card_exist)
-				val &= ~L1OFF_MBIAS2_EN_5250;
-			else
-				val |= L1OFF_MBIAS2_EN_5250;
-		}
-	}
-	rtsx_set_l1off_sub(pcr, val);
-}
-
-static const struct pcr_ops rts524a_pcr_ops = {
-	.write_phy = rts524a_write_phy,
-	.read_phy = rts524a_read_phy,
-	.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
-	.extra_init_hw = rts524a_extra_init_hw,
-	.optimize_phy = rts524a_optimize_phy,
-	.turn_on_led = rtsx_base_turn_on_led,
-	.turn_off_led = rtsx_base_turn_off_led,
-	.enable_auto_blink = rtsx_base_enable_auto_blink,
-	.disable_auto_blink = rtsx_base_disable_auto_blink,
-	.card_power_on = rtsx_base_card_power_on,
-	.card_power_off = rtsx_base_card_power_off,
-	.switch_output_voltage = rtsx_base_switch_output_voltage,
-	.force_power_down = rtsx_base_force_power_down,
-	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
-	.set_aspm = rts5249_set_aspm,
-};
-
-void rts524a_init_params(struct rtsx_pcr *pcr)
-{
-	rts5249_init_params(pcr);
-	pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
-	pcr->option.ltr_l1off_snooze_sspwrgate =
-		LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
-
-	pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
-	pcr->ops = &rts524a_pcr_ops;
-}
-
-static int rts525a_card_power_on(struct rtsx_pcr *pcr, int card)
-{
-	rtsx_pci_write_register(pcr, LDO_VCC_CFG1,
-		LDO_VCC_TUNE_MASK, LDO_VCC_3V3);
-	return rtsx_base_card_power_on(pcr, card);
-}
-
-static int rts525a_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	switch (voltage) {
-	case OUTPUT_3V3:
-		rtsx_pci_write_register(pcr, LDO_CONFIG2,
-			LDO_D3318_MASK, LDO_D3318_33V);
-		rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8, 0);
-		break;
-	case OUTPUT_1V8:
-		rtsx_pci_write_register(pcr, LDO_CONFIG2,
-			LDO_D3318_MASK, LDO_D3318_18V);
-		rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8,
-			SD_IO_USING_1V8);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	rtsx_pci_init_cmd(pcr);
-	rts5249_fill_driving(pcr, voltage);
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-static int rts525a_optimize_phy(struct rtsx_pcr *pcr)
-{
-	int err;
-
-	err = rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
-		D3_DELINK_MODE_EN, 0x00);
-	if (err < 0)
-		return err;
-
-	rtsx_pci_write_phy_register(pcr, _PHY_FLD0,
-		_PHY_FLD0_CLK_REQ_20C | _PHY_FLD0_RX_IDLE_EN |
-		_PHY_FLD0_BIT_ERR_RSTN | _PHY_FLD0_BER_COUNT |
-		_PHY_FLD0_BER_TIMER | _PHY_FLD0_CHECK_EN);
-
-	rtsx_pci_write_phy_register(pcr, _PHY_ANA03,
-		_PHY_ANA03_TIMER_MAX | _PHY_ANA03_OOBS_DEB_EN |
-		_PHY_CMU_DEBUG_EN);
-
-	if (is_version(pcr, 0x525A, IC_VER_A))
-		rtsx_pci_write_phy_register(pcr, _PHY_REV0,
-			_PHY_REV0_FILTER_OUT | _PHY_REV0_CDR_BYPASS_PFD |
-			_PHY_REV0_CDR_RX_IDLE_BYPASS);
-
-	return 0;
-}
-
-static int rts525a_extra_init_hw(struct rtsx_pcr *pcr)
-{
-	rts5249_extra_init_hw(pcr);
-
-	rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL);
-	if (is_version(pcr, 0x525A, IC_VER_A)) {
-		rtsx_pci_write_register(pcr, L1SUB_CONFIG2,
-			L1SUB_AUTO_CFG, L1SUB_AUTO_CFG);
-		rtsx_pci_write_register(pcr, RREF_CFG,
-			RREF_VBGSEL_MASK, RREF_VBGSEL_1V25);
-		rtsx_pci_write_register(pcr, LDO_VIO_CFG,
-			LDO_VIO_TUNE_MASK, LDO_VIO_1V7);
-		rtsx_pci_write_register(pcr, LDO_DV12S_CFG,
-			LDO_D12_TUNE_MASK, LDO_D12_TUNE_DF);
-		rtsx_pci_write_register(pcr, LDO_AV12S_CFG,
-			LDO_AV12S_TUNE_MASK, LDO_AV12S_TUNE_DF);
-		rtsx_pci_write_register(pcr, LDO_VCC_CFG0,
-			LDO_VCC_LMTVTH_MASK, LDO_VCC_LMTVTH_2A);
-		rtsx_pci_write_register(pcr, OOBS_CONFIG,
-			OOBS_AUTOK_DIS | OOBS_VAL_MASK, 0x89);
-	}
-
-	return 0;
-}
-
-static const struct pcr_ops rts525a_pcr_ops = {
-	.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
-	.extra_init_hw = rts525a_extra_init_hw,
-	.optimize_phy = rts525a_optimize_phy,
-	.turn_on_led = rtsx_base_turn_on_led,
-	.turn_off_led = rtsx_base_turn_off_led,
-	.enable_auto_blink = rtsx_base_enable_auto_blink,
-	.disable_auto_blink = rtsx_base_disable_auto_blink,
-	.card_power_on = rts525a_card_power_on,
-	.card_power_off = rtsx_base_card_power_off,
-	.switch_output_voltage = rts525a_switch_output_voltage,
-	.force_power_down = rtsx_base_force_power_down,
-	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
-	.set_aspm = rts5249_set_aspm,
-};
-
-void rts525a_init_params(struct rtsx_pcr *pcr)
-{
-	rts5249_init_params(pcr);
-	pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
-	pcr->option.ltr_l1off_snooze_sspwrgate =
-		LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
-
-	pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
-	pcr->ops = &rts525a_pcr_ops;
-}
-
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
deleted file mode 100644
index c3ed885..0000000
--- a/drivers/mfd/rtsx_pcr.c
+++ /dev/null
@@ -1,1572 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- */
-
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/highmem.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/idr.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/rtsx_pci.h>
-#include <linux/mmc/card.h>
-#include <asm/unaligned.h>
-
-#include "rtsx_pcr.h"
-
-static bool msi_en = true;
-module_param(msi_en, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msi_en, "Enable MSI");
-
-static DEFINE_IDR(rtsx_pci_idr);
-static DEFINE_SPINLOCK(rtsx_pci_lock);
-
-static struct mfd_cell rtsx_pcr_cells[] = {
-	[RTSX_SD_CARD] = {
-		.name = DRV_NAME_RTSX_PCI_SDMMC,
-	},
-	[RTSX_MS_CARD] = {
-		.name = DRV_NAME_RTSX_PCI_MS,
-	},
-};
-
-static const struct pci_device_id rtsx_pci_ids[] = {
-	{ PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x522A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x5286), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x524A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ PCI_DEVICE(0x10EC, 0x525A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, rtsx_pci_ids);
-
-static inline void rtsx_pci_enable_aspm(struct rtsx_pcr *pcr)
-{
-	rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL,
-		0xFC, pcr->aspm_en);
-}
-
-static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr)
-{
-	rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL,
-		0xFC, 0);
-}
-
-int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
-{
-	rtsx_pci_write_register(pcr, MSGTXDATA0,
-				MASK_8_BIT_DEF, (u8) (latency & 0xFF));
-	rtsx_pci_write_register(pcr, MSGTXDATA1,
-				MASK_8_BIT_DEF, (u8)((latency >> 8) & 0xFF));
-	rtsx_pci_write_register(pcr, MSGTXDATA2,
-				MASK_8_BIT_DEF, (u8)((latency >> 16) & 0xFF));
-	rtsx_pci_write_register(pcr, MSGTXDATA3,
-				MASK_8_BIT_DEF, (u8)((latency >> 24) & 0xFF));
-	rtsx_pci_write_register(pcr, LTR_CTL, LTR_TX_EN_MASK |
-		LTR_LATENCY_MODE_MASK, LTR_TX_EN_1 | LTR_LATENCY_MODE_SW);
-
-	return 0;
-}
-
-int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
-{
-	if (pcr->ops->set_ltr_latency)
-		return pcr->ops->set_ltr_latency(pcr, latency);
-	else
-		return rtsx_comm_set_ltr_latency(pcr, latency);
-}
-
-static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable)
-{
-	struct rtsx_cr_option *option = &pcr->option;
-
-	if (pcr->aspm_enabled == enable)
-		return;
-
-	if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
-		if (enable)
-			rtsx_pci_enable_aspm(pcr);
-		else
-			rtsx_pci_disable_aspm(pcr);
-	} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
-		u8 mask = FORCE_ASPM_VAL_MASK;
-		u8 val = 0;
-
-		if (enable)
-			val = pcr->aspm_en;
-		rtsx_pci_write_register(pcr, ASPM_FORCE_CTL,  mask, val);
-	}
-
-	pcr->aspm_enabled = enable;
-}
-
-static void rtsx_disable_aspm(struct rtsx_pcr *pcr)
-{
-	if (pcr->ops->set_aspm)
-		pcr->ops->set_aspm(pcr, false);
-	else
-		rtsx_comm_set_aspm(pcr, false);
-}
-
-int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val)
-{
-	rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, val);
-
-	return 0;
-}
-
-void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active)
-{
-	if (pcr->ops->set_l1off_cfg_sub_d0)
-		pcr->ops->set_l1off_cfg_sub_d0(pcr, active);
-}
-
-static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr)
-{
-	struct rtsx_cr_option *option = &pcr->option;
-
-	rtsx_disable_aspm(pcr);
-
-	if (option->ltr_enabled)
-		rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
-
-	if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
-		rtsx_set_l1off_sub_cfg_d0(pcr, 1);
-}
-
-void rtsx_pm_full_on(struct rtsx_pcr *pcr)
-{
-	if (pcr->ops->full_on)
-		pcr->ops->full_on(pcr);
-	else
-		rtsx_comm_pm_full_on(pcr);
-}
-
-void rtsx_pci_start_run(struct rtsx_pcr *pcr)
-{
-	/* If pci device removed, don't queue idle work any more */
-	if (pcr->remove_pci)
-		return;
-
-	if (pcr->state != PDEV_STAT_RUN) {
-		pcr->state = PDEV_STAT_RUN;
-		if (pcr->ops->enable_auto_blink)
-			pcr->ops->enable_auto_blink(pcr);
-		rtsx_pm_full_on(pcr);
-	}
-
-	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
-
-int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data)
-{
-	int i;
-	u32 val = HAIMR_WRITE_START;
-
-	val |= (u32)(addr & 0x3FFF) << 16;
-	val |= (u32)mask << 8;
-	val |= (u32)data;
-
-	rtsx_pci_writel(pcr, RTSX_HAIMR, val);
-
-	for (i = 0; i < MAX_RW_REG_CNT; i++) {
-		val = rtsx_pci_readl(pcr, RTSX_HAIMR);
-		if ((val & HAIMR_TRANS_END) == 0) {
-			if (data != (u8)val)
-				return -EIO;
-			return 0;
-		}
-	}
-
-	return -ETIMEDOUT;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_write_register);
-
-int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data)
-{
-	u32 val = HAIMR_READ_START;
-	int i;
-
-	val |= (u32)(addr & 0x3FFF) << 16;
-	rtsx_pci_writel(pcr, RTSX_HAIMR, val);
-
-	for (i = 0; i < MAX_RW_REG_CNT; i++) {
-		val = rtsx_pci_readl(pcr, RTSX_HAIMR);
-		if ((val & HAIMR_TRANS_END) == 0)
-			break;
-	}
-
-	if (i >= MAX_RW_REG_CNT)
-		return -ETIMEDOUT;
-
-	if (data)
-		*data = (u8)(val & 0xFF);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_read_register);
-
-int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val)
-{
-	int err, i, finished = 0;
-	u8 tmp;
-
-	rtsx_pci_init_cmd(pcr);
-
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8));
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81);
-
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	for (i = 0; i < 100000; i++) {
-		err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
-		if (err < 0)
-			return err;
-
-		if (!(tmp & 0x80)) {
-			finished = 1;
-			break;
-		}
-	}
-
-	if (!finished)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
-int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val)
-{
-	if (pcr->ops->write_phy)
-		return pcr->ops->write_phy(pcr, addr, val);
-
-	return __rtsx_pci_write_phy_register(pcr, addr, val);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_write_phy_register);
-
-int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
-{
-	int err, i, finished = 0;
-	u16 data;
-	u8 *ptr, tmp;
-
-	rtsx_pci_init_cmd(pcr);
-
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80);
-
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	for (i = 0; i < 100000; i++) {
-		err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
-		if (err < 0)
-			return err;
-
-		if (!(tmp & 0x80)) {
-			finished = 1;
-			break;
-		}
-	}
-
-	if (!finished)
-		return -ETIMEDOUT;
-
-	rtsx_pci_init_cmd(pcr);
-
-	rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0);
-	rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0);
-
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	ptr = rtsx_pci_get_cmd_data(pcr);
-	data = ((u16)ptr[1] << 8) | ptr[0];
-
-	if (val)
-		*val = data;
-
-	return 0;
-}
-
-int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
-{
-	if (pcr->ops->read_phy)
-		return pcr->ops->read_phy(pcr, addr, val);
-
-	return __rtsx_pci_read_phy_register(pcr, addr, val);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register);
-
-void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr)
-{
-	rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
-	rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
-
-	rtsx_pci_write_register(pcr, DMACTL, 0x80, 0x80);
-	rtsx_pci_write_register(pcr, RBCTL, 0x80, 0x80);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_stop_cmd);
-
-void rtsx_pci_add_cmd(struct rtsx_pcr *pcr,
-		u8 cmd_type, u16 reg_addr, u8 mask, u8 data)
-{
-	unsigned long flags;
-	u32 val = 0;
-	u32 *ptr = (u32 *)(pcr->host_cmds_ptr);
-
-	val |= (u32)(cmd_type & 0x03) << 30;
-	val |= (u32)(reg_addr & 0x3FFF) << 16;
-	val |= (u32)mask << 8;
-	val |= (u32)data;
-
-	spin_lock_irqsave(&pcr->lock, flags);
-	ptr += pcr->ci;
-	if (pcr->ci < (HOST_CMDS_BUF_LEN / 4)) {
-		put_unaligned_le32(val, ptr);
-		ptr++;
-		pcr->ci++;
-	}
-	spin_unlock_irqrestore(&pcr->lock, flags);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_add_cmd);
-
-void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr)
-{
-	u32 val = 1 << 31;
-
-	rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
-
-	val |= (u32)(pcr->ci * 4) & 0x00FFFFFF;
-	/* Hardware Auto Response */
-	val |= 0x40000000;
-	rtsx_pci_writel(pcr, RTSX_HCBCTLR, val);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd_no_wait);
-
-int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout)
-{
-	struct completion trans_done;
-	u32 val = 1 << 31;
-	long timeleft;
-	unsigned long flags;
-	int err = 0;
-
-	spin_lock_irqsave(&pcr->lock, flags);
-
-	/* set up data structures for the wakeup system */
-	pcr->done = &trans_done;
-	pcr->trans_result = TRANS_NOT_READY;
-	init_completion(&trans_done);
-
-	rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
-
-	val |= (u32)(pcr->ci * 4) & 0x00FFFFFF;
-	/* Hardware Auto Response */
-	val |= 0x40000000;
-	rtsx_pci_writel(pcr, RTSX_HCBCTLR, val);
-
-	spin_unlock_irqrestore(&pcr->lock, flags);
-
-	/* Wait for TRANS_OK_INT */
-	timeleft = wait_for_completion_interruptible_timeout(
-			&trans_done, msecs_to_jiffies(timeout));
-	if (timeleft <= 0) {
-		pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__);
-		err = -ETIMEDOUT;
-		goto finish_send_cmd;
-	}
-
-	spin_lock_irqsave(&pcr->lock, flags);
-	if (pcr->trans_result == TRANS_RESULT_FAIL)
-		err = -EINVAL;
-	else if (pcr->trans_result == TRANS_RESULT_OK)
-		err = 0;
-	else if (pcr->trans_result == TRANS_NO_DEVICE)
-		err = -ENODEV;
-	spin_unlock_irqrestore(&pcr->lock, flags);
-
-finish_send_cmd:
-	spin_lock_irqsave(&pcr->lock, flags);
-	pcr->done = NULL;
-	spin_unlock_irqrestore(&pcr->lock, flags);
-
-	if ((err < 0) && (err != -ENODEV))
-		rtsx_pci_stop_cmd(pcr);
-
-	if (pcr->finish_me)
-		complete(pcr->finish_me);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd);
-
-static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
-		dma_addr_t addr, unsigned int len, int end)
-{
-	u64 *ptr = (u64 *)(pcr->host_sg_tbl_ptr) + pcr->sgi;
-	u64 val;
-	u8 option = SG_VALID | SG_TRANS_DATA;
-
-	pcr_dbg(pcr, "DMA addr: 0x%x, Len: 0x%x\n", (unsigned int)addr, len);
-
-	if (end)
-		option |= SG_END;
-	val = ((u64)addr << 32) | ((u64)len << 12) | option;
-
-	put_unaligned_le64(val, ptr);
-	pcr->sgi++;
-}
-
-int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int num_sg, bool read, int timeout)
-{
-	int err = 0, count;
-
-	pcr_dbg(pcr, "--> %s: num_sg = %d\n", __func__, num_sg);
-	count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
-	if (count < 1)
-		return -EINVAL;
-	pcr_dbg(pcr, "DMA mapping count: %d\n", count);
-
-	err = rtsx_pci_dma_transfer(pcr, sglist, count, read, timeout);
-
-	rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
-
-int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int num_sg, bool read)
-{
-	enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
-	if (pcr->remove_pci)
-		return -EINVAL;
-
-	if ((sglist == NULL) || (num_sg <= 0))
-		return -EINVAL;
-
-	return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
-
-void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int num_sg, bool read)
-{
-	enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
-	dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
-
-int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int count, bool read, int timeout)
-{
-	struct completion trans_done;
-	struct scatterlist *sg;
-	dma_addr_t addr;
-	long timeleft;
-	unsigned long flags;
-	unsigned int len;
-	int i, err = 0;
-	u32 val;
-	u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
-
-	if (pcr->remove_pci)
-		return -ENODEV;
-
-	if ((sglist == NULL) || (count < 1))
-		return -EINVAL;
-
-	val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
-	pcr->sgi = 0;
-	for_each_sg(sglist, sg, count, i) {
-		addr = sg_dma_address(sg);
-		len = sg_dma_len(sg);
-		rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
-	}
-
-	spin_lock_irqsave(&pcr->lock, flags);
-
-	pcr->done = &trans_done;
-	pcr->trans_result = TRANS_NOT_READY;
-	init_completion(&trans_done);
-	rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
-	rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
-
-	spin_unlock_irqrestore(&pcr->lock, flags);
-
-	timeleft = wait_for_completion_interruptible_timeout(
-			&trans_done, msecs_to_jiffies(timeout));
-	if (timeleft <= 0) {
-		pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__);
-		err = -ETIMEDOUT;
-		goto out;
-	}
-
-	spin_lock_irqsave(&pcr->lock, flags);
-	if (pcr->trans_result == TRANS_RESULT_FAIL) {
-		err = -EILSEQ;
-		if (pcr->dma_error_count < RTS_MAX_TIMES_FREQ_REDUCTION)
-			pcr->dma_error_count++;
-	}
-
-	else if (pcr->trans_result == TRANS_NO_DEVICE)
-		err = -ENODEV;
-	spin_unlock_irqrestore(&pcr->lock, flags);
-
-out:
-	spin_lock_irqsave(&pcr->lock, flags);
-	pcr->done = NULL;
-	spin_unlock_irqrestore(&pcr->lock, flags);
-
-	if ((err < 0) && (err != -ENODEV))
-		rtsx_pci_stop_cmd(pcr);
-
-	if (pcr->finish_me)
-		complete(pcr->finish_me);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
-
-int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
-{
-	int err;
-	int i, j;
-	u16 reg;
-	u8 *ptr;
-
-	if (buf_len > 512)
-		buf_len = 512;
-
-	ptr = buf;
-	reg = PPBUF_BASE2;
-	for (i = 0; i < buf_len / 256; i++) {
-		rtsx_pci_init_cmd(pcr);
-
-		for (j = 0; j < 256; j++)
-			rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0);
-
-		err = rtsx_pci_send_cmd(pcr, 250);
-		if (err < 0)
-			return err;
-
-		memcpy(ptr, rtsx_pci_get_cmd_data(pcr), 256);
-		ptr += 256;
-	}
-
-	if (buf_len % 256) {
-		rtsx_pci_init_cmd(pcr);
-
-		for (j = 0; j < buf_len % 256; j++)
-			rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0);
-
-		err = rtsx_pci_send_cmd(pcr, 250);
-		if (err < 0)
-			return err;
-	}
-
-	memcpy(ptr, rtsx_pci_get_cmd_data(pcr), buf_len % 256);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_read_ppbuf);
-
-int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
-{
-	int err;
-	int i, j;
-	u16 reg;
-	u8 *ptr;
-
-	if (buf_len > 512)
-		buf_len = 512;
-
-	ptr = buf;
-	reg = PPBUF_BASE2;
-	for (i = 0; i < buf_len / 256; i++) {
-		rtsx_pci_init_cmd(pcr);
-
-		for (j = 0; j < 256; j++) {
-			rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-					reg++, 0xFF, *ptr);
-			ptr++;
-		}
-
-		err = rtsx_pci_send_cmd(pcr, 250);
-		if (err < 0)
-			return err;
-	}
-
-	if (buf_len % 256) {
-		rtsx_pci_init_cmd(pcr);
-
-		for (j = 0; j < buf_len % 256; j++) {
-			rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-					reg++, 0xFF, *ptr);
-			ptr++;
-		}
-
-		err = rtsx_pci_send_cmd(pcr, 250);
-		if (err < 0)
-			return err;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_write_ppbuf);
-
-static int rtsx_pci_set_pull_ctl(struct rtsx_pcr *pcr, const u32 *tbl)
-{
-	rtsx_pci_init_cmd(pcr);
-
-	while (*tbl & 0xFFFF0000) {
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-				(u16)(*tbl >> 16), 0xFF, (u8)(*tbl));
-		tbl++;
-	}
-
-	return rtsx_pci_send_cmd(pcr, 100);
-}
-
-int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card)
-{
-	const u32 *tbl;
-
-	if (card == RTSX_SD_CARD)
-		tbl = pcr->sd_pull_ctl_enable_tbl;
-	else if (card == RTSX_MS_CARD)
-		tbl = pcr->ms_pull_ctl_enable_tbl;
-	else
-		return -EINVAL;
-
-	return rtsx_pci_set_pull_ctl(pcr, tbl);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_enable);
-
-int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card)
-{
-	const u32 *tbl;
-
-	if (card == RTSX_SD_CARD)
-		tbl = pcr->sd_pull_ctl_disable_tbl;
-	else if (card == RTSX_MS_CARD)
-		tbl = pcr->ms_pull_ctl_disable_tbl;
-	else
-		return -EINVAL;
-
-
-	return rtsx_pci_set_pull_ctl(pcr, tbl);
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_disable);
-
-static void rtsx_pci_enable_bus_int(struct rtsx_pcr *pcr)
-{
-	pcr->bier = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN | SD_INT_EN;
-
-	if (pcr->num_slots > 1)
-		pcr->bier |= MS_INT_EN;
-
-	/* Enable Bus Interrupt */
-	rtsx_pci_writel(pcr, RTSX_BIER, pcr->bier);
-
-	pcr_dbg(pcr, "RTSX_BIER: 0x%08x\n", pcr->bier);
-}
-
-static inline u8 double_ssc_depth(u8 depth)
-{
-	return ((depth > 1) ? (depth - 1) : depth);
-}
-
-static u8 revise_ssc_depth(u8 ssc_depth, u8 div)
-{
-	if (div > CLK_DIV_1) {
-		if (ssc_depth > (div - 1))
-			ssc_depth -= (div - 1);
-		else
-			ssc_depth = SSC_DEPTH_4M;
-	}
-
-	return ssc_depth;
-}
-
-int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
-		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
-{
-	int err, clk;
-	u8 n, clk_divider, mcu_cnt, div;
-	static const u8 depth[] = {
-		[RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M,
-		[RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M,
-		[RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M,
-		[RTSX_SSC_DEPTH_500K] = SSC_DEPTH_500K,
-		[RTSX_SSC_DEPTH_250K] = SSC_DEPTH_250K,
-	};
-
-	if (initial_mode) {
-		/* We use 250k(around) here, in initial stage */
-		clk_divider = SD_CLK_DIVIDE_128;
-		card_clock = 30000000;
-	} else {
-		clk_divider = SD_CLK_DIVIDE_0;
-	}
-	err = rtsx_pci_write_register(pcr, SD_CFG1,
-			SD_CLK_DIVIDE_MASK, clk_divider);
-	if (err < 0)
-		return err;
-
-	/* Reduce card clock by 20MHz each time a DMA transfer error occurs */
-	if (card_clock == UHS_SDR104_MAX_DTR &&
-	    pcr->dma_error_count &&
-	    PCI_PID(pcr) == RTS5227_DEVICE_ID)
-		card_clock = UHS_SDR104_MAX_DTR -
-			(pcr->dma_error_count * 20000000);
-
-	card_clock /= 1000000;
-	pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock);
-
-	clk = card_clock;
-	if (!initial_mode && double_clk)
-		clk = card_clock * 2;
-	pcr_dbg(pcr, "Internal SSC clock: %dMHz (cur_clock = %d)\n",
-		clk, pcr->cur_clock);
-
-	if (clk == pcr->cur_clock)
-		return 0;
-
-	if (pcr->ops->conv_clk_and_div_n)
-		n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
-	else
-		n = (u8)(clk - 2);
-	if ((clk <= 2) || (n > MAX_DIV_N_PCR))
-		return -EINVAL;
-
-	mcu_cnt = (u8)(125/clk + 3);
-	if (mcu_cnt > 15)
-		mcu_cnt = 15;
-
-	/* Make sure that the SSC clock div_n is not less than MIN_DIV_N_PCR */
-	div = CLK_DIV_1;
-	while ((n < MIN_DIV_N_PCR) && (div < CLK_DIV_8)) {
-		if (pcr->ops->conv_clk_and_div_n) {
-			int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
-					DIV_N_TO_CLK) * 2;
-			n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
-					CLK_TO_DIV_N);
-		} else {
-			n = (n + 2) * 2 - 2;
-		}
-		div++;
-	}
-	pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
-
-	ssc_depth = depth[ssc_depth];
-	if (double_clk)
-		ssc_depth = double_ssc_depth(ssc_depth);
-
-	ssc_depth = revise_ssc_depth(ssc_depth, div);
-	pcr_dbg(pcr, "ssc_depth = %d\n", ssc_depth);
-
-	rtsx_pci_init_cmd(pcr);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL,
-			CLK_LOW_FREQ, CLK_LOW_FREQ);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV,
-			0xFF, (div << 4) | mcu_cnt);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
-			SSC_DEPTH_MASK, ssc_depth);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
-	if (vpclk) {
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
-				PHASE_NOT_RESET, 0);
-		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
-				PHASE_NOT_RESET, PHASE_NOT_RESET);
-	}
-
-	err = rtsx_pci_send_cmd(pcr, 2000);
-	if (err < 0)
-		return err;
-
-	/* Wait SSC clock stable */
-	udelay(10);
-	err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
-	if (err < 0)
-		return err;
-
-	pcr->cur_clock = clk;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_switch_clock);
-
-int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card)
-{
-	if (pcr->ops->card_power_on)
-		return pcr->ops->card_power_on(pcr, card);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_card_power_on);
-
-int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card)
-{
-	if (pcr->ops->card_power_off)
-		return pcr->ops->card_power_off(pcr, card);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off);
-
-int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card)
-{
-	static const unsigned int cd_mask[] = {
-		[RTSX_SD_CARD] = SD_EXIST,
-		[RTSX_MS_CARD] = MS_EXIST
-	};
-
-	if (!(pcr->flags & PCR_MS_PMOS)) {
-		/* When using single PMOS, accessing card is not permitted
-		 * if the existing card is not the designated one.
-		 */
-		if (pcr->card_exist & (~cd_mask[card]))
-			return -EIO;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_card_exclusive_check);
-
-int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
-{
-	if (pcr->ops->switch_output_voltage)
-		return pcr->ops->switch_output_voltage(pcr, voltage);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_switch_output_voltage);
-
-unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr)
-{
-	unsigned int val;
-
-	val = rtsx_pci_readl(pcr, RTSX_BIPR);
-	if (pcr->ops->cd_deglitch)
-		val = pcr->ops->cd_deglitch(pcr);
-
-	return val;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_card_exist);
-
-void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr)
-{
-	struct completion finish;
-
-	pcr->finish_me = &finish;
-	init_completion(&finish);
-
-	if (pcr->done)
-		complete(pcr->done);
-
-	if (!pcr->remove_pci)
-		rtsx_pci_stop_cmd(pcr);
-
-	wait_for_completion_interruptible_timeout(&finish,
-			msecs_to_jiffies(2));
-	pcr->finish_me = NULL;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_complete_unfinished_transfer);
-
-static void rtsx_pci_card_detect(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	struct rtsx_pcr *pcr;
-	unsigned long flags;
-	unsigned int card_detect = 0, card_inserted, card_removed;
-	u32 irq_status;
-
-	dwork = to_delayed_work(work);
-	pcr = container_of(dwork, struct rtsx_pcr, carddet_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-	spin_lock_irqsave(&pcr->lock, flags);
-
-	irq_status = rtsx_pci_readl(pcr, RTSX_BIPR);
-	pcr_dbg(pcr, "irq_status: 0x%08x\n", irq_status);
-
-	irq_status &= CARD_EXIST;
-	card_inserted = pcr->card_inserted & irq_status;
-	card_removed = pcr->card_removed;
-	pcr->card_inserted = 0;
-	pcr->card_removed = 0;
-
-	spin_unlock_irqrestore(&pcr->lock, flags);
-
-	if (card_inserted || card_removed) {
-		pcr_dbg(pcr, "card_inserted: 0x%x, card_removed: 0x%x\n",
-			card_inserted, card_removed);
-
-		if (pcr->ops->cd_deglitch)
-			card_inserted = pcr->ops->cd_deglitch(pcr);
-
-		card_detect = card_inserted | card_removed;
-
-		pcr->card_exist |= card_inserted;
-		pcr->card_exist &= ~card_removed;
-	}
-
-	mutex_unlock(&pcr->pcr_mutex);
-
-	if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event)
-		pcr->slots[RTSX_SD_CARD].card_event(
-				pcr->slots[RTSX_SD_CARD].p_dev);
-	if ((card_detect & MS_EXIST) && pcr->slots[RTSX_MS_CARD].card_event)
-		pcr->slots[RTSX_MS_CARD].card_event(
-				pcr->slots[RTSX_MS_CARD].p_dev);
-}
-
-static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
-{
-	struct rtsx_pcr *pcr = dev_id;
-	u32 int_reg;
-
-	if (!pcr)
-		return IRQ_NONE;
-
-	spin_lock(&pcr->lock);
-
-	int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
-	/* Clear interrupt flag */
-	rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
-	if ((int_reg & pcr->bier) == 0) {
-		spin_unlock(&pcr->lock);
-		return IRQ_NONE;
-	}
-	if (int_reg == 0xFFFFFFFF) {
-		spin_unlock(&pcr->lock);
-		return IRQ_HANDLED;
-	}
-
-	int_reg &= (pcr->bier | 0x7FFFFF);
-
-	if (int_reg & SD_INT) {
-		if (int_reg & SD_EXIST) {
-			pcr->card_inserted |= SD_EXIST;
-		} else {
-			pcr->card_removed |= SD_EXIST;
-			pcr->card_inserted &= ~SD_EXIST;
-		}
-		pcr->dma_error_count = 0;
-	}
-
-	if (int_reg & MS_INT) {
-		if (int_reg & MS_EXIST) {
-			pcr->card_inserted |= MS_EXIST;
-		} else {
-			pcr->card_removed |= MS_EXIST;
-			pcr->card_inserted &= ~MS_EXIST;
-		}
-	}
-
-	if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
-		if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
-			pcr->trans_result = TRANS_RESULT_FAIL;
-			if (pcr->done)
-				complete(pcr->done);
-		} else if (int_reg & TRANS_OK_INT) {
-			pcr->trans_result = TRANS_RESULT_OK;
-			if (pcr->done)
-				complete(pcr->done);
-		}
-	}
-
-	if (pcr->card_inserted || pcr->card_removed)
-		schedule_delayed_work(&pcr->carddet_work,
-				msecs_to_jiffies(200));
-
-	spin_unlock(&pcr->lock);
-	return IRQ_HANDLED;
-}
-
-static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr)
-{
-	pcr_dbg(pcr, "%s: pcr->msi_en = %d, pci->irq = %d\n",
-			__func__, pcr->msi_en, pcr->pci->irq);
-
-	if (request_irq(pcr->pci->irq, rtsx_pci_isr,
-			pcr->msi_en ? 0 : IRQF_SHARED,
-			DRV_NAME_RTSX_PCI, pcr)) {
-		dev_err(&(pcr->pci->dev),
-			"rtsx_sdmmc: unable to grab IRQ %d, disabling device\n",
-			pcr->pci->irq);
-		return -1;
-	}
-
-	pcr->irq = pcr->pci->irq;
-	pci_intx(pcr->pci, !pcr->msi_en);
-
-	return 0;
-}
-
-static void rtsx_enable_aspm(struct rtsx_pcr *pcr)
-{
-	if (pcr->ops->set_aspm)
-		pcr->ops->set_aspm(pcr, true);
-	else
-		rtsx_comm_set_aspm(pcr, true);
-}
-
-static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr)
-{
-	struct rtsx_cr_option *option = &pcr->option;
-
-	if (option->ltr_enabled) {
-		u32 latency = option->ltr_l1off_latency;
-
-		if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN))
-			mdelay(option->l1_snooze_delay);
-
-		rtsx_set_ltr_latency(pcr, latency);
-	}
-
-	if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
-		rtsx_set_l1off_sub_cfg_d0(pcr, 0);
-
-	rtsx_enable_aspm(pcr);
-}
-
-void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
-{
-	if (pcr->ops->power_saving)
-		pcr->ops->power_saving(pcr);
-	else
-		rtsx_comm_pm_power_saving(pcr);
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-	pcr_dbg(pcr, "--> %s\n", __func__);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pcr->state = PDEV_STAT_IDLE;
-
-	if (pcr->ops->disable_auto_blink)
-		pcr->ops->disable_auto_blink(pcr);
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pm_power_saving(pcr);
-
-	mutex_unlock(&pcr->pcr_mutex);
-}
-
-#ifdef CONFIG_PM
-static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
-{
-	if (pcr->ops->turn_off_led)
-		pcr->ops->turn_off_led(pcr);
-
-	rtsx_pci_writel(pcr, RTSX_BIER, 0);
-	pcr->bier = 0;
-
-	rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08);
-	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
-
-	if (pcr->ops->force_power_down)
-		pcr->ops->force_power_down(pcr, pm_state);
-}
-#endif
-
-static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
-{
-	int err;
-
-	pcr->pcie_cap = pci_find_capability(pcr->pci, PCI_CAP_ID_EXP);
-	rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
-
-	rtsx_pci_enable_bus_int(pcr);
-
-	/* Power on SSC */
-	err = rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, 0);
-	if (err < 0)
-		return err;
-
-	/* Wait SSC power stable */
-	udelay(200);
-
-	rtsx_pci_disable_aspm(pcr);
-	if (pcr->ops->optimize_phy) {
-		err = pcr->ops->optimize_phy(pcr);
-		if (err < 0)
-			return err;
-	}
-
-	rtsx_pci_init_cmd(pcr);
-
-	/* Set mcu_cnt to 7 to ensure data can be sampled properly */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, 0x07, 0x07);
-
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00);
-	/* Disable card clock */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0);
-	/* Reset delink mode */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0);
-	/* Card driving select */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL,
-			0xFF, pcr->card_drive_sel);
-	/* Enable SSC Clock */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1,
-			0xFF, SSC_8X_EN | SSC_SEL_4M);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12);
-	/* Disable cd_pwr_save */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x16, 0x10);
-	/* Clear Link Ready Interrupt */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0,
-			LINK_RDY_INT, LINK_RDY_INT);
-	/* Enlarge the estimation window of PERST# glitch
-	 * to reduce the chance of invalid card interrupt
-	 */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PERST_GLITCH_WIDTH, 0xFF, 0x80);
-	/* Update RC oscillator to 400k
-	 * bit[0] F_HIGH: for RC oscillator, Rst_value is 1'b1
-	 *                1: 2M  0: 400k
-	 */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RCCTL, 0x01, 0x00);
-	/* Set interrupt write clear
-	 * bit 1: U_elbi_if_rd_clr_en
-	 *	1: Enable ELBI interrupt[31:22] & [7:0] flag read clear
-	 *	0: ELBI interrupt flag[31:22] & [7:0] only can be write clear
-	 */
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0);
-
-	err = rtsx_pci_send_cmd(pcr, 100);
-	if (err < 0)
-		return err;
-
-	switch (PCI_PID(pcr)) {
-	case PID_5250:
-	case PID_524A:
-	case PID_525A:
-		rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
-		break;
-	default:
-		break;
-	}
-
-	/* Enable clk_request_n to enable clock power management */
-	rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1);
-	/* Enter L1 when host tx idle */
-	rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B);
-
-	if (pcr->ops->extra_init_hw) {
-		err = pcr->ops->extra_init_hw(pcr);
-		if (err < 0)
-			return err;
-	}
-
-	/* No CD interrupt if probing driver with card inserted.
-	 * So we need to initialize pcr->card_exist here.
-	 */
-	if (pcr->ops->cd_deglitch)
-		pcr->card_exist = pcr->ops->cd_deglitch(pcr);
-	else
-		pcr->card_exist = rtsx_pci_readl(pcr, RTSX_BIPR) & CARD_EXIST;
-
-	return 0;
-}
-
-static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
-{
-	int err;
-
-	spin_lock_init(&pcr->lock);
-	mutex_init(&pcr->pcr_mutex);
-
-	switch (PCI_PID(pcr)) {
-	default:
-	case 0x5209:
-		rts5209_init_params(pcr);
-		break;
-
-	case 0x5229:
-		rts5229_init_params(pcr);
-		break;
-
-	case 0x5289:
-		rtl8411_init_params(pcr);
-		break;
-
-	case 0x5227:
-		rts5227_init_params(pcr);
-		break;
-
-	case 0x522A:
-		rts522a_init_params(pcr);
-		break;
-
-	case 0x5249:
-		rts5249_init_params(pcr);
-		break;
-
-	case 0x524A:
-		rts524a_init_params(pcr);
-		break;
-
-	case 0x525A:
-		rts525a_init_params(pcr);
-		break;
-
-	case 0x5287:
-		rtl8411b_init_params(pcr);
-		break;
-
-	case 0x5286:
-		rtl8402_init_params(pcr);
-		break;
-	}
-
-	pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n",
-			PCI_PID(pcr), pcr->ic_version);
-
-	pcr->slots = kcalloc(pcr->num_slots, sizeof(struct rtsx_slot),
-			GFP_KERNEL);
-	if (!pcr->slots)
-		return -ENOMEM;
-
-	if (pcr->ops->fetch_vendor_settings)
-		pcr->ops->fetch_vendor_settings(pcr);
-
-	pcr_dbg(pcr, "pcr->aspm_en = 0x%x\n", pcr->aspm_en);
-	pcr_dbg(pcr, "pcr->sd30_drive_sel_1v8 = 0x%x\n",
-			pcr->sd30_drive_sel_1v8);
-	pcr_dbg(pcr, "pcr->sd30_drive_sel_3v3 = 0x%x\n",
-			pcr->sd30_drive_sel_3v3);
-	pcr_dbg(pcr, "pcr->card_drive_sel = 0x%x\n",
-			pcr->card_drive_sel);
-	pcr_dbg(pcr, "pcr->flags = 0x%x\n", pcr->flags);
-
-	pcr->state = PDEV_STAT_IDLE;
-	err = rtsx_pci_init_hw(pcr);
-	if (err < 0) {
-		kfree(pcr->slots);
-		return err;
-	}
-
-	return 0;
-}
-
-static int rtsx_pci_probe(struct pci_dev *pcidev,
-			  const struct pci_device_id *id)
-{
-	struct rtsx_pcr *pcr;
-	struct pcr_handle *handle;
-	u32 base, len;
-	int ret, i, bar = 0;
-
-	dev_dbg(&(pcidev->dev),
-		": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n",
-		pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device,
-		(int)pcidev->revision);
-
-	ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
-	if (ret < 0)
-		return ret;
-
-	ret = pci_enable_device(pcidev);
-	if (ret)
-		return ret;
-
-	ret = pci_request_regions(pcidev, DRV_NAME_RTSX_PCI);
-	if (ret)
-		goto disable;
-
-	pcr = kzalloc(sizeof(*pcr), GFP_KERNEL);
-	if (!pcr) {
-		ret = -ENOMEM;
-		goto release_pci;
-	}
-
-	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
-	if (!handle) {
-		ret = -ENOMEM;
-		goto free_pcr;
-	}
-	handle->pcr = pcr;
-
-	idr_preload(GFP_KERNEL);
-	spin_lock(&rtsx_pci_lock);
-	ret = idr_alloc(&rtsx_pci_idr, pcr, 0, 0, GFP_NOWAIT);
-	if (ret >= 0)
-		pcr->id = ret;
-	spin_unlock(&rtsx_pci_lock);
-	idr_preload_end();
-	if (ret < 0)
-		goto free_handle;
-
-	pcr->pci = pcidev;
-	dev_set_drvdata(&pcidev->dev, handle);
-
-	if (CHK_PCI_PID(pcr, 0x525A))
-		bar = 1;
-	len = pci_resource_len(pcidev, bar);
-	base = pci_resource_start(pcidev, bar);
-	pcr->remap_addr = ioremap_nocache(base, len);
-	if (!pcr->remap_addr) {
-		ret = -ENOMEM;
-		goto free_handle;
-	}
-
-	pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev),
-			RTSX_RESV_BUF_LEN, &(pcr->rtsx_resv_buf_addr),
-			GFP_KERNEL);
-	if (pcr->rtsx_resv_buf == NULL) {
-		ret = -ENXIO;
-		goto unmap;
-	}
-	pcr->host_cmds_ptr = pcr->rtsx_resv_buf;
-	pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr;
-	pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN;
-	pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN;
-
-	pcr->card_inserted = 0;
-	pcr->card_removed = 0;
-	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
-
-	pcr->msi_en = msi_en;
-	if (pcr->msi_en) {
-		ret = pci_enable_msi(pcidev);
-		if (ret)
-			pcr->msi_en = false;
-	}
-
-	ret = rtsx_pci_acquire_irq(pcr);
-	if (ret < 0)
-		goto disable_msi;
-
-	pci_set_master(pcidev);
-	synchronize_irq(pcr->irq);
-
-	ret = rtsx_pci_init_chip(pcr);
-	if (ret < 0)
-		goto disable_irq;
-
-	for (i = 0; i < ARRAY_SIZE(rtsx_pcr_cells); i++) {
-		rtsx_pcr_cells[i].platform_data = handle;
-		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
-	}
-	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
-			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
-	if (ret < 0)
-		goto disable_irq;
-
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
-	return 0;
-
-disable_irq:
-	free_irq(pcr->irq, (void *)pcr);
-disable_msi:
-	if (pcr->msi_en)
-		pci_disable_msi(pcr->pci);
-	dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN,
-			pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr);
-unmap:
-	iounmap(pcr->remap_addr);
-free_handle:
-	kfree(handle);
-free_pcr:
-	kfree(pcr);
-release_pci:
-	pci_release_regions(pcidev);
-disable:
-	pci_disable_device(pcidev);
-
-	return ret;
-}
-
-static void rtsx_pci_remove(struct pci_dev *pcidev)
-{
-	struct pcr_handle *handle = pci_get_drvdata(pcidev);
-	struct rtsx_pcr *pcr = handle->pcr;
-
-	pcr->remove_pci = true;
-
-	/* Disable interrupts at the pcr level */
-	spin_lock_irq(&pcr->lock);
-	rtsx_pci_writel(pcr, RTSX_BIER, 0);
-	pcr->bier = 0;
-	spin_unlock_irq(&pcr->lock);
-
-	cancel_delayed_work_sync(&pcr->carddet_work);
-	cancel_delayed_work_sync(&pcr->idle_work);
-
-	mfd_remove_devices(&pcidev->dev);
-
-	dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN,
-			pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr);
-	free_irq(pcr->irq, (void *)pcr);
-	if (pcr->msi_en)
-		pci_disable_msi(pcr->pci);
-	iounmap(pcr->remap_addr);
-
-	pci_release_regions(pcidev);
-	pci_disable_device(pcidev);
-
-	spin_lock(&rtsx_pci_lock);
-	idr_remove(&rtsx_pci_idr, pcr->id);
-	spin_unlock(&rtsx_pci_lock);
-
-	kfree(pcr->slots);
-	kfree(pcr);
-	kfree(handle);
-
-	dev_dbg(&(pcidev->dev),
-		": Realtek PCI-E Card Reader at %s [%04x:%04x] has been removed\n",
-		pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
-}
-
-#ifdef CONFIG_PM
-
-static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
-{
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
-
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
-
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
-	cancel_delayed_work(&pcr->carddet_work);
-	cancel_delayed_work(&pcr->idle_work);
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
-
-	pci_save_state(pcidev);
-	pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
-	pci_disable_device(pcidev);
-	pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
-
-	mutex_unlock(&pcr->pcr_mutex);
-	return 0;
-}
-
-static int rtsx_pci_resume(struct pci_dev *pcidev)
-{
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
-	int ret = 0;
-
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
-
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-
-	mutex_lock(&pcr->pcr_mutex);
-
-	pci_set_power_state(pcidev, PCI_D0);
-	pci_restore_state(pcidev);
-	ret = pci_enable_device(pcidev);
-	if (ret)
-		goto out;
-	pci_set_master(pcidev);
-
-	ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
-	if (ret)
-		goto out;
-
-	ret = rtsx_pci_init_hw(pcr);
-	if (ret)
-		goto out;
-
-	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
-out:
-	mutex_unlock(&pcr->pcr_mutex);
-	return ret;
-}
-
-static void rtsx_pci_shutdown(struct pci_dev *pcidev)
-{
-	struct pcr_handle *handle;
-	struct rtsx_pcr *pcr;
-
-	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
-
-	handle = pci_get_drvdata(pcidev);
-	pcr = handle->pcr;
-	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
-
-	pci_disable_device(pcidev);
-	free_irq(pcr->irq, (void *)pcr);
-	if (pcr->msi_en)
-		pci_disable_msi(pcr->pci);
-}
-
-#else /* CONFIG_PM */
-
-#define rtsx_pci_suspend NULL
-#define rtsx_pci_resume NULL
-#define rtsx_pci_shutdown NULL
-
-#endif /* CONFIG_PM */
-
-static struct pci_driver rtsx_pci_driver = {
-	.name = DRV_NAME_RTSX_PCI,
-	.id_table = rtsx_pci_ids,
-	.probe = rtsx_pci_probe,
-	.remove = rtsx_pci_remove,
-	.suspend = rtsx_pci_suspend,
-	.resume = rtsx_pci_resume,
-	.shutdown = rtsx_pci_shutdown,
-};
-module_pci_driver(rtsx_pci_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>");
-MODULE_DESCRIPTION("Realtek PCI-E Card Reader Driver");
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h
deleted file mode 100644
index ec784e0..0000000
--- a/drivers/mfd/rtsx_pcr.h
+++ /dev/null
@@ -1,103 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- */
-
-#ifndef __RTSX_PCR_H
-#define __RTSX_PCR_H
-
-#include <linux/mfd/rtsx_pci.h>
-
-#define MIN_DIV_N_PCR		80
-#define MAX_DIV_N_PCR		208
-
-#define RTS522A_PM_CTRL3		0xFF7E
-
-#define RTS524A_PME_FORCE_CTL		0xFF78
-#define RTS524A_PM_CTRL3		0xFF7E
-
-#define LTR_ACTIVE_LATENCY_DEF		0x883C
-#define LTR_IDLE_LATENCY_DEF		0x892C
-#define LTR_L1OFF_LATENCY_DEF		0x9003
-#define L1_SNOOZE_DELAY_DEF		1
-#define LTR_L1OFF_SSPWRGATE_5249_DEF		0xAF
-#define LTR_L1OFF_SSPWRGATE_5250_DEF		0xFF
-#define LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF	0xAC
-#define LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF	0xF8
-#define CMD_TIMEOUT_DEF		100
-#define ASPM_MASK_NEG		0xFC
-#define MASK_8_BIT_DEF		0xFF
-
-int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
-int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
-
-void rts5209_init_params(struct rtsx_pcr *pcr);
-void rts5229_init_params(struct rtsx_pcr *pcr);
-void rtl8411_init_params(struct rtsx_pcr *pcr);
-void rtl8402_init_params(struct rtsx_pcr *pcr);
-void rts5227_init_params(struct rtsx_pcr *pcr);
-void rts522a_init_params(struct rtsx_pcr *pcr);
-void rts5249_init_params(struct rtsx_pcr *pcr);
-void rts524a_init_params(struct rtsx_pcr *pcr);
-void rts525a_init_params(struct rtsx_pcr *pcr);
-void rtl8411b_init_params(struct rtsx_pcr *pcr);
-
-static inline u8 map_sd_drive(int idx)
-{
-	u8 sd_drive[4] = {
-		0x01,	/* Type D */
-		0x02,	/* Type C */
-		0x05,	/* Type A */
-		0x03	/* Type B */
-	};
-
-	return sd_drive[idx];
-}
-
-#define rtsx_vendor_setting_valid(reg)		(!((reg) & 0x1000000))
-#define rts5209_vendor_setting1_valid(reg)	(!((reg) & 0x80))
-#define rts5209_vendor_setting2_valid(reg)	((reg) & 0x80)
-
-#define rtsx_reg_to_aspm(reg)			(((reg) >> 28) & 0x03)
-#define rtsx_reg_to_sd30_drive_sel_1v8(reg)	(((reg) >> 26) & 0x03)
-#define rtsx_reg_to_sd30_drive_sel_3v3(reg)	(((reg) >> 5) & 0x03)
-#define rtsx_reg_to_card_drive_sel(reg)		((((reg) >> 25) & 0x01) << 6)
-#define rtsx_reg_check_reverse_socket(reg)	((reg) & 0x4000)
-#define rts5209_reg_to_aspm(reg)		(((reg) >> 5) & 0x03)
-#define rts5209_reg_check_ms_pmos(reg)		(!((reg) & 0x08))
-#define rts5209_reg_to_sd30_drive_sel_1v8(reg)	(((reg) >> 3) & 0x07)
-#define rts5209_reg_to_sd30_drive_sel_3v3(reg)	((reg) & 0x07)
-#define rts5209_reg_to_card_drive_sel(reg)	((reg) >> 8)
-#define rtl8411_reg_to_sd30_drive_sel_3v3(reg)	(((reg) >> 5) & 0x07)
-#define rtl8411b_reg_to_sd30_drive_sel_3v3(reg)	((reg) & 0x03)
-
-#define set_pull_ctrl_tables(pcr, __device)				\
-do {									\
-	pcr->sd_pull_ctl_enable_tbl  = __device##_sd_pull_ctl_enable_tbl;  \
-	pcr->sd_pull_ctl_disable_tbl = __device##_sd_pull_ctl_disable_tbl; \
-	pcr->ms_pull_ctl_enable_tbl  = __device##_ms_pull_ctl_enable_tbl;  \
-	pcr->ms_pull_ctl_disable_tbl = __device##_ms_pull_ctl_disable_tbl; \
-} while (0)
-
-/* generic operations */
-int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
-int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency);
-int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val);
-
-#endif
diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c
deleted file mode 100644
index 59d61b0..0000000
--- a/drivers/mfd/rtsx_usb.c
+++ /dev/null
@@ -1,791 +0,0 @@ 
-/* Driver for Realtek USB card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Roger Tseng <rogerable@realtek.com>
- */
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/usb.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/rtsx_usb.h>
-
-static int polling_pipe = 1;
-module_param(polling_pipe, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)");
-
-static const struct mfd_cell rtsx_usb_cells[] = {
-	[RTSX_USB_SD_CARD] = {
-		.name = "rtsx_usb_sdmmc",
-		.pdata_size = 0,
-	},
-	[RTSX_USB_MS_CARD] = {
-		.name = "rtsx_usb_ms",
-		.pdata_size = 0,
-	},
-};
-
-static void rtsx_usb_sg_timed_out(struct timer_list *t)
-{
-	struct rtsx_ucr *ucr = from_timer(ucr, t, sg_timer);
-
-	dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
-	usb_sg_cancel(&ucr->current_sg);
-}
-
-static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
-		unsigned int pipe, struct scatterlist *sg, int num_sg,
-		unsigned int length, unsigned int *act_len, int timeout)
-{
-	int ret;
-
-	dev_dbg(&ucr->pusb_intf->dev, "%s: xfer %u bytes, %d entries\n",
-			__func__, length, num_sg);
-	ret = usb_sg_init(&ucr->current_sg, ucr->pusb_dev, pipe, 0,
-			sg, num_sg, length, GFP_NOIO);
-	if (ret)
-		return ret;
-
-	ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
-	add_timer(&ucr->sg_timer);
-	usb_sg_wait(&ucr->current_sg);
-	if (!del_timer_sync(&ucr->sg_timer))
-		ret = -ETIMEDOUT;
-	else
-		ret = ucr->current_sg.status;
-
-	if (act_len)
-		*act_len = ucr->current_sg.bytes;
-
-	return ret;
-}
-
-int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
-			      void *buf, unsigned int len, int num_sg,
-			      unsigned int *act_len, int timeout)
-{
-	if (timeout < 600)
-		timeout = 600;
-
-	if (num_sg)
-		return rtsx_usb_bulk_transfer_sglist(ucr, pipe,
-				(struct scatterlist *)buf, num_sg, len, act_len,
-				timeout);
-	else
-		return usb_bulk_msg(ucr->pusb_dev, pipe, buf, len, act_len,
-				timeout);
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_transfer_data);
-
-static inline void rtsx_usb_seq_cmd_hdr(struct rtsx_ucr *ucr,
-		u16 addr, u16 len, u8 seq_type)
-{
-	rtsx_usb_cmd_hdr_tag(ucr);
-
-	ucr->cmd_buf[PACKET_TYPE] = seq_type;
-	ucr->cmd_buf[5] = (u8)(len >> 8);
-	ucr->cmd_buf[6] = (u8)len;
-	ucr->cmd_buf[8] = (u8)(addr >> 8);
-	ucr->cmd_buf[9] = (u8)addr;
-
-	if (seq_type == SEQ_WRITE)
-		ucr->cmd_buf[STAGE_FLAG] = 0;
-	else
-		ucr->cmd_buf[STAGE_FLAG] = STAGE_R;
-}
-
-static int rtsx_usb_seq_write_register(struct rtsx_ucr *ucr,
-		u16 addr, u16 len, u8 *data)
-{
-	u16 cmd_len = ALIGN(SEQ_WRITE_DATA_OFFSET + len, 4);
-
-	if (!data)
-		return -EINVAL;
-
-	if (cmd_len > IOBUF_SIZE)
-		return -EINVAL;
-
-	rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_WRITE);
-	memcpy(ucr->cmd_buf + SEQ_WRITE_DATA_OFFSET, data, len);
-
-	return rtsx_usb_transfer_data(ucr,
-			usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
-			ucr->cmd_buf, cmd_len, 0, NULL, 100);
-}
-
-static int rtsx_usb_seq_read_register(struct rtsx_ucr *ucr,
-		u16 addr, u16 len, u8 *data)
-{
-	int i, ret;
-	u16 rsp_len = round_down(len, 4);
-	u16 res_len = len - rsp_len;
-
-	if (!data)
-		return -EINVAL;
-
-	/* 4-byte aligned part */
-	if (rsp_len) {
-		rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_READ);
-		ret = rtsx_usb_transfer_data(ucr,
-				usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
-				ucr->cmd_buf, 12, 0, NULL, 100);
-		if (ret)
-			return ret;
-
-		ret = rtsx_usb_transfer_data(ucr,
-				usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
-				data, rsp_len, 0, NULL, 100);
-		if (ret)
-			return ret;
-	}
-
-	/* unaligned part */
-	for (i = 0; i < res_len; i++) {
-		ret = rtsx_usb_read_register(ucr, addr + rsp_len + i,
-				data + rsp_len + i);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
-{
-	return rtsx_usb_seq_read_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_read_ppbuf);
-
-int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
-{
-	return rtsx_usb_seq_write_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_write_ppbuf);
-
-int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr,
-		u8 mask, u8 data)
-{
-	u16 value, index;
-
-	addr |= EP0_WRITE_REG_CMD << EP0_OP_SHIFT;
-	value = swab16(addr);
-	index = mask | data << 8;
-
-	return usb_control_msg(ucr->pusb_dev,
-			usb_sndctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
-			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			value, index, NULL, 0, 100);
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
-
-int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
-{
-	u16 value;
-	u8 *buf;
-	int ret;
-
-	if (!data)
-		return -EINVAL;
-
-	buf = kzalloc(sizeof(u8), GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
-	value = swab16(addr);
-
-	ret = usb_control_msg(ucr->pusb_dev,
-			usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
-			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			value, 0, buf, 1, 100);
-	*data = *buf;
-
-	kfree(buf);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
-
-void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type, u16 reg_addr,
-		u8 mask, u8 data)
-{
-	int i;
-
-	if (ucr->cmd_idx < (IOBUF_SIZE - CMD_OFFSET) / 4) {
-		i = CMD_OFFSET + ucr->cmd_idx * 4;
-
-		ucr->cmd_buf[i++] = ((cmd_type & 0x03) << 6) |
-			(u8)((reg_addr >> 8) & 0x3F);
-		ucr->cmd_buf[i++] = (u8)reg_addr;
-		ucr->cmd_buf[i++] = mask;
-		ucr->cmd_buf[i++] = data;
-
-		ucr->cmd_idx++;
-	}
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_add_cmd);
-
-int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout)
-{
-	int ret;
-
-	ucr->cmd_buf[CNT_H] = (u8)(ucr->cmd_idx >> 8);
-	ucr->cmd_buf[CNT_L] = (u8)(ucr->cmd_idx);
-	ucr->cmd_buf[STAGE_FLAG] = flag;
-
-	ret = rtsx_usb_transfer_data(ucr,
-			usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
-			ucr->cmd_buf, ucr->cmd_idx * 4 + CMD_OFFSET,
-			0, NULL, timeout);
-	if (ret) {
-		rtsx_usb_clear_fsm_err(ucr);
-		return ret;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_send_cmd);
-
-int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout)
-{
-	if (rsp_len <= 0)
-		return -EINVAL;
-
-	rsp_len = ALIGN(rsp_len, 4);
-
-	return rtsx_usb_transfer_data(ucr,
-			usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
-			ucr->rsp_buf, rsp_len, 0, NULL, timeout);
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_get_rsp);
-
-static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
-{
-	int ret;
-
-	rtsx_usb_init_cmd(ucr);
-	rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_EXIST, 0x00, 0x00);
-	rtsx_usb_add_cmd(ucr, READ_REG_CMD, OCPSTAT, 0x00, 0x00);
-	ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
-	if (ret)
-		return ret;
-
-	ret = rtsx_usb_get_rsp(ucr, 2, 100);
-	if (ret)
-		return ret;
-
-	*status = ((ucr->rsp_buf[0] >> 2) & 0x0f) |
-		  ((ucr->rsp_buf[1] & 0x03) << 4);
-
-	return 0;
-}
-
-int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
-{
-	int ret;
-	u16 *buf;
-
-	if (!status)
-		return -EINVAL;
-
-	if (polling_pipe == 0) {
-		buf = kzalloc(sizeof(u16), GFP_KERNEL);
-		if (!buf)
-			return -ENOMEM;
-
-		ret = usb_control_msg(ucr->pusb_dev,
-				usb_rcvctrlpipe(ucr->pusb_dev, 0),
-				RTSX_USB_REQ_POLL,
-				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-				0, 0, buf, 2, 100);
-		*status = *buf;
-
-		kfree(buf);
-	} else {
-		ret = rtsx_usb_get_status_with_bulk(ucr, status);
-	}
-
-	/* usb_control_msg may return positive when success */
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_get_card_status);
-
-static int rtsx_usb_write_phy_register(struct rtsx_ucr *ucr, u8 addr, u8 val)
-{
-	dev_dbg(&ucr->pusb_intf->dev, "Write 0x%x to phy register 0x%x\n",
-			val, addr);
-
-	rtsx_usb_init_cmd(ucr);
-
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VSTAIN, 0xFF, val);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL,
-			0xFF, (addr >> 4) & 0x0F);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
-
-	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
-}
-
-int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask, u8 data)
-{
-	rtsx_usb_init_cmd(ucr);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, addr, mask, data);
-	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_write_register);
-
-int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
-{
-	int ret;
-
-	if (data != NULL)
-		*data = 0;
-
-	rtsx_usb_init_cmd(ucr);
-	rtsx_usb_add_cmd(ucr, READ_REG_CMD, addr, 0, 0);
-	ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
-	if (ret)
-		return ret;
-
-	ret = rtsx_usb_get_rsp(ucr, 1, 100);
-	if (ret)
-		return ret;
-
-	if (data != NULL)
-		*data = ucr->rsp_buf[0];
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_read_register);
-
-static inline u8 double_ssc_depth(u8 depth)
-{
-	return (depth > 1) ? (depth - 1) : depth;
-}
-
-static u8 revise_ssc_depth(u8 ssc_depth, u8 div)
-{
-	if (div > CLK_DIV_1) {
-		if (ssc_depth > div - 1)
-			ssc_depth -= (div - 1);
-		else
-			ssc_depth = SSC_DEPTH_2M;
-	}
-
-	return ssc_depth;
-}
-
-int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock,
-		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
-{
-	int ret;
-	u8 n, clk_divider, mcu_cnt, div;
-
-	if (!card_clock) {
-		ucr->cur_clk = 0;
-		return 0;
-	}
-
-	if (initial_mode) {
-		/* We use 250k(around) here, in initial stage */
-		clk_divider = SD_CLK_DIVIDE_128;
-		card_clock = 30000000;
-	} else {
-		clk_divider = SD_CLK_DIVIDE_0;
-	}
-
-	ret = rtsx_usb_write_register(ucr, SD_CFG1,
-			SD_CLK_DIVIDE_MASK, clk_divider);
-	if (ret < 0)
-		return ret;
-
-	card_clock /= 1000000;
-	dev_dbg(&ucr->pusb_intf->dev,
-			"Switch card clock to %dMHz\n", card_clock);
-
-	if (!initial_mode && double_clk)
-		card_clock *= 2;
-	dev_dbg(&ucr->pusb_intf->dev,
-			"Internal SSC clock: %dMHz (cur_clk = %d)\n",
-			card_clock, ucr->cur_clk);
-
-	if (card_clock == ucr->cur_clk)
-		return 0;
-
-	/* Converting clock value into internal settings: n and div */
-	n = card_clock - 2;
-	if ((card_clock <= 2) || (n > MAX_DIV_N))
-		return -EINVAL;
-
-	mcu_cnt = 60/card_clock + 3;
-	if (mcu_cnt > 15)
-		mcu_cnt = 15;
-
-	/* Make sure that the SSC clock div_n is not less than MIN_DIV_N */
-
-	div = CLK_DIV_1;
-	while (n < MIN_DIV_N && div < CLK_DIV_4) {
-		n = (n + 2) * 2 - 2;
-		div++;
-	}
-	dev_dbg(&ucr->pusb_intf->dev, "n = %d, div = %d\n", n, div);
-
-	if (double_clk)
-		ssc_depth = double_ssc_depth(ssc_depth);
-
-	ssc_depth = revise_ssc_depth(ssc_depth, div);
-	dev_dbg(&ucr->pusb_intf->dev, "ssc_depth = %d\n", ssc_depth);
-
-	rtsx_usb_init_cmd(ucr);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV,
-			0x3F, (div << 4) | mcu_cnt);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL2,
-			SSC_DEPTH_MASK, ssc_depth);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
-	if (vpclk) {
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
-				PHASE_NOT_RESET, 0);
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
-				PHASE_NOT_RESET, PHASE_NOT_RESET);
-	}
-
-	ret = rtsx_usb_send_cmd(ucr, MODE_C, 2000);
-	if (ret < 0)
-		return ret;
-
-	ret = rtsx_usb_write_register(ucr, SSC_CTL1, 0xff,
-			SSC_RSTB | SSC_8X_EN | SSC_SEL_4M);
-	if (ret < 0)
-		return ret;
-
-	/* Wait SSC clock stable */
-	usleep_range(100, 1000);
-
-	ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0);
-	if (ret < 0)
-		return ret;
-
-	ucr->cur_clk = card_clock;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_switch_clock);
-
-int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card)
-{
-	int ret;
-	u16 val;
-	u16 cd_mask[] = {
-		[RTSX_USB_SD_CARD] = (CD_MASK & ~SD_CD),
-		[RTSX_USB_MS_CARD] = (CD_MASK & ~MS_CD)
-	};
-
-	ret = rtsx_usb_get_card_status(ucr, &val);
-	/*
-	 * If get status fails, return 0 (ok) for the exclusive check
-	 * and let the flow fail at somewhere else.
-	 */
-	if (ret)
-		return 0;
-
-	if (val & cd_mask[card])
-		return -EIO;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(rtsx_usb_card_exclusive_check);
-
-static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr)
-{
-	int ret;
-	u8 val;
-
-	rtsx_usb_init_cmd(ucr);
-
-	if (CHECK_PKG(ucr, LQFP48)) {
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
-				LDO3318_PWR_MASK, LDO_SUSPEND);
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
-				FORCE_LDO_POWERB, FORCE_LDO_POWERB);
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1,
-				0x30, 0x10);
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5,
-				0x03, 0x01);
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6,
-				0x0C, 0x04);
-	}
-
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SYS_DUMMY0, NYET_MSAK, NYET_EN);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CD_DEGLITCH_WIDTH, 0xFF, 0x08);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
-			CD_DEGLITCH_EN, XD_CD_DEGLITCH_EN, 0x0);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD30_DRIVE_SEL,
-			SD30_DRIVE_MASK, DRIVER_TYPE_D);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
-			CARD_DRIVE_SEL, SD20_DRIVE_MASK, 0x0);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, 0xE0, 0x0);
-
-	if (ucr->is_rts5179)
-		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
-				CARD_PULL_CTL5, 0x03, 0x01);
-
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DMA1_CTL,
-		       EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
-	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_INT_PEND,
-			XD_INT | MS_INT | SD_INT,
-			XD_INT | MS_INT | SD_INT);
-
-	ret = rtsx_usb_send_cmd(ucr, MODE_C, 100);
-	if (ret)
-		return ret;
-
-	/* config non-crystal mode */
-	rtsx_usb_read_register(ucr, CFG_MODE, &val);
-	if ((val & XTAL_FREE) || ((val & CLK_MODE_MASK) == CLK_MODE_NON_XTAL)) {
-		ret = rtsx_usb_write_phy_register(ucr, 0xC2, 0x7C);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int rtsx_usb_init_chip(struct rtsx_ucr *ucr)
-{
-	int ret;
-	u8 val;
-
-	rtsx_usb_clear_fsm_err(ucr);
-
-	/* power on SSC */
-	ret = rtsx_usb_write_register(ucr,
-			FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
-	if (ret)
-		return ret;
-
-	usleep_range(100, 1000);
-	ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0x00);
-	if (ret)
-		return ret;
-
-	/* determine IC version */
-	ret = rtsx_usb_read_register(ucr, HW_VERSION, &val);
-	if (ret)
-		return ret;
-
-	ucr->ic_version = val & HW_VER_MASK;
-
-	/* determine package */
-	ret = rtsx_usb_read_register(ucr, CARD_SHARE_MODE, &val);
-	if (ret)
-		return ret;
-
-	if (val & CARD_SHARE_LQFP_SEL) {
-		ucr->package = LQFP48;
-		dev_dbg(&ucr->pusb_intf->dev, "Package: LQFP48\n");
-	} else {
-		ucr->package = QFN24;
-		dev_dbg(&ucr->pusb_intf->dev, "Package: QFN24\n");
-	}
-
-	/* determine IC variations */
-	rtsx_usb_read_register(ucr, CFG_MODE_1, &val);
-	if (val & RTS5179) {
-		ucr->is_rts5179 = true;
-		dev_dbg(&ucr->pusb_intf->dev, "Device is rts5179\n");
-	} else {
-		ucr->is_rts5179 = false;
-	}
-
-	return rtsx_usb_reset_chip(ucr);
-}
-
-static int rtsx_usb_probe(struct usb_interface *intf,
-			 const struct usb_device_id *id)
-{
-	struct usb_device *usb_dev = interface_to_usbdev(intf);
-	struct rtsx_ucr *ucr;
-	int ret;
-
-	dev_dbg(&intf->dev,
-		": Realtek USB Card Reader found at bus %03d address %03d\n",
-		 usb_dev->bus->busnum, usb_dev->devnum);
-
-	ucr = devm_kzalloc(&intf->dev, sizeof(*ucr), GFP_KERNEL);
-	if (!ucr)
-		return -ENOMEM;
-
-	ucr->pusb_dev = usb_dev;
-
-	ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
-			GFP_KERNEL, &ucr->iobuf_dma);
-	if (!ucr->iobuf)
-		return -ENOMEM;
-
-	usb_set_intfdata(intf, ucr);
-
-	ucr->vendor_id = id->idVendor;
-	ucr->product_id = id->idProduct;
-	ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
-
-	mutex_init(&ucr->dev_mutex);
-
-	ucr->pusb_intf = intf;
-
-	/* initialize */
-	ret = rtsx_usb_init_chip(ucr);
-	if (ret)
-		goto out_init_fail;
-
-	/* initialize USB SG transfer timer */
-	timer_setup(&ucr->sg_timer, rtsx_usb_sg_timed_out, 0);
-
-	ret = mfd_add_hotplug_devices(&intf->dev, rtsx_usb_cells,
-				      ARRAY_SIZE(rtsx_usb_cells));
-	if (ret)
-		goto out_init_fail;
-
-#ifdef CONFIG_PM
-	intf->needs_remote_wakeup = 1;
-	usb_enable_autosuspend(usb_dev);
-#endif
-
-	return 0;
-
-out_init_fail:
-	usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-			ucr->iobuf_dma);
-	return ret;
-}
-
-static void rtsx_usb_disconnect(struct usb_interface *intf)
-{
-	struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
-
-	dev_dbg(&intf->dev, "%s called\n", __func__);
-
-	mfd_remove_devices(&intf->dev);
-
-	usb_set_intfdata(ucr->pusb_intf, NULL);
-	usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-			ucr->iobuf_dma);
-}
-
-#ifdef CONFIG_PM
-static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
-{
-	struct rtsx_ucr *ucr =
-		(struct rtsx_ucr *)usb_get_intfdata(intf);
-	u16 val = 0;
-
-	dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n",
-			__func__, message.event);
-
-	if (PMSG_IS_AUTO(message)) {
-		if (mutex_trylock(&ucr->dev_mutex)) {
-			rtsx_usb_get_card_status(ucr, &val);
-			mutex_unlock(&ucr->dev_mutex);
-
-			/* Defer the autosuspend if card exists */
-			if (val & (SD_CD | MS_CD))
-				return -EAGAIN;
-		} else {
-			/* There is an ongoing operation*/
-			return -EAGAIN;
-		}
-	}
-
-	return 0;
-}
-
-static int rtsx_usb_resume(struct usb_interface *intf)
-{
-	return 0;
-}
-
-static int rtsx_usb_reset_resume(struct usb_interface *intf)
-{
-	struct rtsx_ucr *ucr =
-		(struct rtsx_ucr *)usb_get_intfdata(intf);
-
-	rtsx_usb_reset_chip(ucr);
-	return 0;
-}
-
-#else /* CONFIG_PM */
-
-#define rtsx_usb_suspend NULL
-#define rtsx_usb_resume NULL
-#define rtsx_usb_reset_resume NULL
-
-#endif /* CONFIG_PM */
-
-
-static int rtsx_usb_pre_reset(struct usb_interface *intf)
-{
-	struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
-
-	mutex_lock(&ucr->dev_mutex);
-	return 0;
-}
-
-static int rtsx_usb_post_reset(struct usb_interface *intf)
-{
-	struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
-
-	mutex_unlock(&ucr->dev_mutex);
-	return 0;
-}
-
-static struct usb_device_id rtsx_usb_usb_ids[] = {
-	{ USB_DEVICE(0x0BDA, 0x0129) },
-	{ USB_DEVICE(0x0BDA, 0x0139) },
-	{ USB_DEVICE(0x0BDA, 0x0140) },
-	{ }
-};
-MODULE_DEVICE_TABLE(usb, rtsx_usb_usb_ids);
-
-static struct usb_driver rtsx_usb_driver = {
-	.name			= "rtsx_usb",
-	.probe			= rtsx_usb_probe,
-	.disconnect		= rtsx_usb_disconnect,
-	.suspend		= rtsx_usb_suspend,
-	.resume			= rtsx_usb_resume,
-	.reset_resume		= rtsx_usb_reset_resume,
-	.pre_reset		= rtsx_usb_pre_reset,
-	.post_reset		= rtsx_usb_post_reset,
-	.id_table		= rtsx_usb_usb_ids,
-	.supports_autosuspend	= 1,
-	.soft_unbind		= 1,
-};
-
-module_usb_driver(rtsx_usb_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
-MODULE_DESCRIPTION("Realtek USB Card Reader Driver");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0534f33..ffdbf14 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -496,6 +496,10 @@  config PCI_ENDPOINT_TEST
            Enable this configuration option to enable the host side test driver
            for PCI Endpoint.
 
+config MISC_RTSX
+	tristate
+	default MISC_RTSX_PCI || MISC_RTSX_USB
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
@@ -509,4 +513,5 @@  source "drivers/misc/genwqe/Kconfig"
 source "drivers/misc/echo/Kconfig"
 source "drivers/misc/cxl/Kconfig"
 source "drivers/misc/ocxl/Kconfig"
+source "drivers/misc/cardreader/Kconfig"
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 73326d5..c3c8624 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,6 +56,7 @@  obj-$(CONFIG_ASPEED_LPC_CTRL)	+= aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
+obj-$(CONFIG_MISC_RTSX)		+= cardreader/
 
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o
 lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o
diff --git a/drivers/misc/cardreader/Kconfig b/drivers/misc/cardreader/Kconfig
new file mode 100644
index 0000000..e7d835a
--- /dev/null
+++ b/drivers/misc/cardreader/Kconfig
@@ -0,0 +1,20 @@ 
+config MISC_RTSX_PCI
+	tristate "Realtek PCI-E card reader"
+	depends on PCI
+	select MFD_CORE
+	help
+	  This supports for Realtek PCI-Express card reader including rts5209,
+	  rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411.
+	  Realtek card readers support access to many types of memory cards,
+	  such as Memory Stick, Memory Stick Pro, Secure Digital and
+	  MultiMediaCard.
+
+config MISC_RTSX_USB
+	tristate "Realtek USB card reader"
+	depends on USB
+	select MFD_CORE
+	help
+	  Select this option to get support for Realtek USB 2.0 card readers
+	  including RTS5129, RTS5139, RTS5179 and RTS5170.
+	  Realtek card reader supports access to many types of memory cards,
+	  such as Memory Stick Pro, Secure Digital and MultiMediaCard.
diff --git a/drivers/misc/cardreader/Makefile b/drivers/misc/cardreader/Makefile
new file mode 100644
index 0000000..78337b2
--- /dev/null
+++ b/drivers/misc/cardreader/Makefile
@@ -0,0 +1,4 @@ 
+rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
+
+obj-$(CONFIG_MISC_RTSX_PCI)	+= rtsx_pci.o
+obj-$(CONFIG_MISC_RTSX_USB)	+= rtsx_usb.o
diff --git a/drivers/misc/cardreader/rtl8411.c b/drivers/misc/cardreader/rtl8411.c
new file mode 100644
index 0000000..434fd07
--- /dev/null
+++ b/drivers/misc/cardreader/rtl8411.c
@@ -0,0 +1,508 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ *   Roger Tseng <rogerable@realtek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/rtsx_pci.h>
+
+#include "rtsx_pcr.h"
+
+static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr)
+{
+	u8 val;
+
+	rtsx_pci_read_register(pcr, SYS_VER, &val);
+	return val & 0x0F;
+}
+
+static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
+{
+	u8 val = 0;
+
+	rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val);
+
+	if (val & 0x2)
+		return 1;
+	else
+		return 0;
+}
+
+static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+	u32 reg1 = 0;
+	u8 reg3 = 0;
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg1);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1);
+
+	if (!rtsx_vendor_setting_valid(reg1))
+		return;
+
+	pcr->aspm_en = rtsx_reg_to_aspm(reg1);
+	pcr->sd30_drive_sel_1v8 =
+		map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg1));
+	pcr->card_drive_sel &= 0x3F;
+	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1);
+
+	rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, &reg3);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3);
+	pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3);
+}
+
+static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+	u32 reg = 0;
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+	if (!rtsx_vendor_setting_valid(reg))
+		return;
+
+	pcr->aspm_en = rtsx_reg_to_aspm(reg);
+	pcr->sd30_drive_sel_1v8 =
+		map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg));
+	pcr->sd30_drive_sel_3v3 =
+		map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
+}
+
+static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
+}
+
+static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	rtsx_pci_init_cmd(pcr);
+
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+			0xFF, pcr->sd30_drive_sel_3v3);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL,
+			CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
+
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	rtsx_pci_init_cmd(pcr);
+
+	if (rtl8411b_is_qfn48(pcr))
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+				CARD_PULL_CTL3, 0xFF, 0xF5);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+			0xFF, pcr->sd30_drive_sel_3v3);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL,
+			CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, FUNC_FORCE_CTL,
+			0x06, 0x00);
+
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rtl8411_turn_on_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
+}
+
+static int rtl8411_turn_off_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01);
+}
+
+static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D);
+}
+
+static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00);
+}
+
+static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+	int err;
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL,
+			BPP_LDO_POWB, BPP_LDO_SUSPEND);
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	/* To avoid too large in-rush current */
+	udelay(150);
+
+	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
+			BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON);
+	if (err < 0)
+		return err;
+
+	udelay(150);
+
+	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
+			BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON);
+	if (err < 0)
+		return err;
+
+	udelay(150);
+
+	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
+			BPP_POWER_MASK, BPP_POWER_ON);
+	if (err < 0)
+		return err;
+
+	return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON);
+}
+
+static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+	int err;
+
+	err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
+			BPP_POWER_MASK, BPP_POWER_OFF);
+	if (err < 0)
+		return err;
+
+	return rtsx_pci_write_register(pcr, LDO_CTL,
+			BPP_LDO_POWB, BPP_LDO_SUSPEND);
+}
+
+static int rtl8411_do_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage,
+		int bpp_tuned18_shift, int bpp_asic_1v8)
+{
+	u8 mask, val;
+	int err;
+
+	mask = (BPP_REG_TUNED18 << bpp_tuned18_shift) | BPP_PAD_MASK;
+	if (voltage == OUTPUT_3V3) {
+		err = rtsx_pci_write_register(pcr,
+				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
+		if (err < 0)
+			return err;
+		val = (BPP_ASIC_3V3 << bpp_tuned18_shift) | BPP_PAD_3V3;
+	} else if (voltage == OUTPUT_1V8) {
+		err = rtsx_pci_write_register(pcr,
+				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
+		if (err < 0)
+			return err;
+		val = (bpp_asic_1v8 << bpp_tuned18_shift) | BPP_PAD_1V8;
+	} else {
+		return -EINVAL;
+	}
+
+	return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
+}
+
+static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	return rtl8411_do_switch_output_voltage(pcr, voltage,
+			BPP_TUNED18_SHIFT_8411, BPP_ASIC_1V8);
+}
+
+static int rtl8402_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	return rtl8411_do_switch_output_voltage(pcr, voltage,
+			BPP_TUNED18_SHIFT_8402, BPP_ASIC_2V0);
+}
+
+static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
+{
+	unsigned int card_exist;
+
+	card_exist = rtsx_pci_readl(pcr, RTSX_BIPR);
+	card_exist &= CARD_EXIST;
+	if (!card_exist) {
+		/* Enable card CD */
+		rtsx_pci_write_register(pcr, CD_PAD_CTL,
+				CD_DISABLE_MASK, CD_ENABLE);
+		/* Enable card interrupt */
+		rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00);
+		return 0;
+	}
+
+	if (hweight32(card_exist) > 1) {
+		rtsx_pci_write_register(pcr, CARD_PWR_CTL,
+				BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON);
+		msleep(100);
+
+		card_exist = rtsx_pci_readl(pcr, RTSX_BIPR);
+		if (card_exist & MS_EXIST)
+			card_exist = MS_EXIST;
+		else if (card_exist & SD_EXIST)
+			card_exist = SD_EXIST;
+		else
+			card_exist = 0;
+
+		rtsx_pci_write_register(pcr, CARD_PWR_CTL,
+				BPP_POWER_MASK, BPP_POWER_OFF);
+
+		pcr_dbg(pcr, "After CD deglitch, card_exist = 0x%x\n",
+			card_exist);
+	}
+
+	if (card_exist & MS_EXIST) {
+		/* Disable SD interrupt */
+		rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40);
+		rtsx_pci_write_register(pcr, CD_PAD_CTL,
+				CD_DISABLE_MASK, MS_CD_EN_ONLY);
+	} else if (card_exist & SD_EXIST) {
+		/* Disable MS interrupt */
+		rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80);
+		rtsx_pci_write_register(pcr, CD_PAD_CTL,
+				CD_DISABLE_MASK, SD_CD_EN_ONLY);
+	}
+
+	return card_exist;
+}
+
+static int rtl8411_conv_clk_and_div_n(int input, int dir)
+{
+	int output;
+
+	if (dir == CLK_TO_DIV_N)
+		output = input * 4 / 5 - 2;
+	else
+		output = (input + 2) * 5 / 4;
+
+	return output;
+}
+
+static const struct pcr_ops rtl8411_pcr_ops = {
+	.fetch_vendor_settings = rtl8411_fetch_vendor_settings,
+	.extra_init_hw = rtl8411_extra_init_hw,
+	.optimize_phy = NULL,
+	.turn_on_led = rtl8411_turn_on_led,
+	.turn_off_led = rtl8411_turn_off_led,
+	.enable_auto_blink = rtl8411_enable_auto_blink,
+	.disable_auto_blink = rtl8411_disable_auto_blink,
+	.card_power_on = rtl8411_card_power_on,
+	.card_power_off = rtl8411_card_power_off,
+	.switch_output_voltage = rtl8411_switch_output_voltage,
+	.cd_deglitch = rtl8411_cd_deglitch,
+	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+	.force_power_down = rtl8411_force_power_down,
+};
+
+static const struct pcr_ops rtl8402_pcr_ops = {
+	.fetch_vendor_settings = rtl8411_fetch_vendor_settings,
+	.extra_init_hw = rtl8411_extra_init_hw,
+	.optimize_phy = NULL,
+	.turn_on_led = rtl8411_turn_on_led,
+	.turn_off_led = rtl8411_turn_off_led,
+	.enable_auto_blink = rtl8411_enable_auto_blink,
+	.disable_auto_blink = rtl8411_disable_auto_blink,
+	.card_power_on = rtl8411_card_power_on,
+	.card_power_off = rtl8411_card_power_off,
+	.switch_output_voltage = rtl8402_switch_output_voltage,
+	.cd_deglitch = rtl8411_cd_deglitch,
+	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+	.force_power_down = rtl8411_force_power_down,
+};
+
+static const struct pcr_ops rtl8411b_pcr_ops = {
+	.fetch_vendor_settings = rtl8411b_fetch_vendor_settings,
+	.extra_init_hw = rtl8411b_extra_init_hw,
+	.optimize_phy = NULL,
+	.turn_on_led = rtl8411_turn_on_led,
+	.turn_off_led = rtl8411_turn_off_led,
+	.enable_auto_blink = rtl8411_enable_auto_blink,
+	.disable_auto_blink = rtl8411_disable_auto_blink,
+	.card_power_on = rtl8411_card_power_on,
+	.card_power_off = rtl8411_card_power_off,
+	.switch_output_voltage = rtl8411_switch_output_voltage,
+	.cd_deglitch = rtl8411_cd_deglitch,
+	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+	.force_power_down = rtl8411_force_power_down,
+};
+
+/* SD Pull Control Enable:
+ *     SD_DAT[3:0] ==> pull up
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull up
+ *     SD_CMD      ==> pull up
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
+	0,
+};
+
+/* SD Pull Control Disable:
+ *     SD_DAT[3:0] ==> pull down
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull down
+ *     SD_CMD      ==> pull down
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
+	0,
+};
+
+/* MS Pull Control Enable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
+	0,
+};
+
+/* MS Pull Control Disable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
+	0,
+};
+
+static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+	0,
+};
+
+static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11),
+	0,
+};
+
+static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+	0,
+};
+
+static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+	0,
+};
+
+static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+	0,
+};
+
+static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+	0,
+};
+
+static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+	0,
+};
+
+static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+	0,
+};
+
+static void rtl8411_init_common_params(struct rtsx_pcr *pcr)
+{
+	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+	pcr->num_slots = 2;
+	pcr->flags = 0;
+	pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT;
+	pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
+	pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
+	pcr->aspm_en = ASPM_L1_EN;
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14);
+	pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10);
+	pcr->ic_version = rtl8411_get_ic_version(pcr);
+}
+
+void rtl8411_init_params(struct rtsx_pcr *pcr)
+{
+	rtl8411_init_common_params(pcr);
+	pcr->ops = &rtl8411_pcr_ops;
+	set_pull_ctrl_tables(pcr, rtl8411);
+}
+
+void rtl8411b_init_params(struct rtsx_pcr *pcr)
+{
+	rtl8411_init_common_params(pcr);
+	pcr->ops = &rtl8411b_pcr_ops;
+	if (rtl8411b_is_qfn48(pcr))
+		set_pull_ctrl_tables(pcr, rtl8411b_qfn48);
+	else
+		set_pull_ctrl_tables(pcr, rtl8411b_qfn64);
+}
+
+void rtl8402_init_params(struct rtsx_pcr *pcr)
+{
+	rtl8411_init_common_params(pcr);
+	pcr->ops = &rtl8402_pcr_ops;
+	set_pull_ctrl_tables(pcr, rtl8411);
+}
diff --git a/drivers/misc/cardreader/rts5209.c b/drivers/misc/cardreader/rts5209.c
new file mode 100644
index 0000000..ce68c48
--- /dev/null
+++ b/drivers/misc/cardreader/rts5209.c
@@ -0,0 +1,277 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/rtsx_pci.h>
+
+#include "rtsx_pcr.h"
+
+static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr)
+{
+	u8 val;
+
+	val = rtsx_pci_readb(pcr, 0x1C);
+	return val & 0x0F;
+}
+
+static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+	u32 reg;
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+	if (rts5209_vendor_setting1_valid(reg)) {
+		if (rts5209_reg_check_ms_pmos(reg))
+			pcr->flags |= PCR_MS_PMOS;
+		pcr->aspm_en = rts5209_reg_to_aspm(reg);
+	}
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+
+	if (rts5209_vendor_setting2_valid(reg)) {
+		pcr->sd30_drive_sel_1v8 =
+			rts5209_reg_to_sd30_drive_sel_1v8(reg);
+		pcr->sd30_drive_sel_3v3 =
+			rts5209_reg_to_sd30_drive_sel_3v3(reg);
+		pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg);
+	}
+}
+
+static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+	rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
+}
+
+static int rts5209_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	rtsx_pci_init_cmd(pcr);
+
+	/* Turn off LED */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03);
+	/* Reset ASPM state to default value */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
+	/* Force CLKREQ# PIN to drive 0 to request clock */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
+	/* Configure GPIO as output */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03);
+	/* Configure driving */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+			0xFF, pcr->sd30_drive_sel_3v3);
+
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5209_optimize_phy(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966);
+}
+
+static int rts5209_turn_on_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
+}
+
+static int rts5209_turn_off_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01);
+}
+
+static int rts5209_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D);
+}
+
+static int rts5209_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00);
+}
+
+static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+	int err;
+	u8 pwr_mask, partial_pwr_on, pwr_on;
+
+	pwr_mask = SD_POWER_MASK;
+	partial_pwr_on = SD_PARTIAL_POWER_ON;
+	pwr_on = SD_POWER_ON;
+
+	if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
+		pwr_mask = MS_POWER_MASK;
+		partial_pwr_on = MS_PARTIAL_POWER_ON;
+		pwr_on = MS_POWER_ON;
+	}
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			pwr_mask, partial_pwr_on);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x04);
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	/* To avoid too large in-rush current */
+	udelay(150);
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x00);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+	u8 pwr_mask, pwr_off;
+
+	pwr_mask = SD_POWER_MASK;
+	pwr_off = SD_POWER_OFF;
+
+	if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
+		pwr_mask = MS_POWER_MASK;
+		pwr_off = MS_POWER_OFF;
+	}
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x06);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	int err;
+
+	if (voltage == OUTPUT_3V3) {
+		err = rtsx_pci_write_register(pcr,
+				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
+		if (err < 0)
+			return err;
+		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
+		if (err < 0)
+			return err;
+	} else if (voltage == OUTPUT_1V8) {
+		err = rtsx_pci_write_register(pcr,
+				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
+		if (err < 0)
+			return err;
+		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
+		if (err < 0)
+			return err;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct pcr_ops rts5209_pcr_ops = {
+	.fetch_vendor_settings = rts5209_fetch_vendor_settings,
+	.extra_init_hw = rts5209_extra_init_hw,
+	.optimize_phy = rts5209_optimize_phy,
+	.turn_on_led = rts5209_turn_on_led,
+	.turn_off_led = rts5209_turn_off_led,
+	.enable_auto_blink = rts5209_enable_auto_blink,
+	.disable_auto_blink = rts5209_disable_auto_blink,
+	.card_power_on = rts5209_card_power_on,
+	.card_power_off = rts5209_card_power_off,
+	.switch_output_voltage = rts5209_switch_output_voltage,
+	.cd_deglitch = NULL,
+	.conv_clk_and_div_n = NULL,
+	.force_power_down = rts5209_force_power_down,
+};
+
+/* SD Pull Control Enable:
+ *     SD_DAT[3:0] ==> pull up
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull up
+ *     SD_CMD      ==> pull up
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5209_sd_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
+	0,
+};
+
+/* SD Pull Control Disable:
+ *     SD_DAT[3:0] ==> pull down
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull down
+ *     SD_CMD      ==> pull down
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5209_sd_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
+	0,
+};
+
+/* MS Pull Control Enable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5209_ms_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+/* MS Pull Control Disable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5209_ms_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+void rts5209_init_params(struct rtsx_pcr *pcr)
+{
+	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 |
+		EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT;
+	pcr->num_slots = 2;
+	pcr->ops = &rts5209_pcr_ops;
+
+	pcr->flags = 0;
+	pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT;
+	pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
+	pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
+	pcr->aspm_en = ASPM_L1_EN;
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16);
+	pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
+
+	pcr->ic_version = rts5209_get_ic_version(pcr);
+	pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl;
+	pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl;
+	pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl;
+	pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl;
+}
diff --git a/drivers/misc/cardreader/rts5227.c b/drivers/misc/cardreader/rts5227.c
new file mode 100644
index 0000000..024dcba
--- /dev/null
+++ b/drivers/misc/cardreader/rts5227.c
@@ -0,0 +1,374 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ *   Roger Tseng <rogerable@realtek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/rtsx_pci.h>
+
+#include "rtsx_pcr.h"
+
+static u8 rts5227_get_ic_version(struct rtsx_pcr *pcr)
+{
+	u8 val;
+
+	rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
+	return val & 0x0F;
+}
+
+static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
+{
+	u8 driving_3v3[4][3] = {
+		{0x13, 0x13, 0x13},
+		{0x96, 0x96, 0x96},
+		{0x7F, 0x7F, 0x7F},
+		{0x96, 0x96, 0x96},
+	};
+	u8 driving_1v8[4][3] = {
+		{0x99, 0x99, 0x99},
+		{0xAA, 0xAA, 0xAA},
+		{0xFE, 0xFE, 0xFE},
+		{0xB3, 0xB3, 0xB3},
+	};
+	u8 (*driving)[3], drive_sel;
+
+	if (voltage == OUTPUT_3V3) {
+		driving = driving_3v3;
+		drive_sel = pcr->sd30_drive_sel_3v3;
+	} else {
+		driving = driving_1v8;
+		drive_sel = pcr->sd30_drive_sel_1v8;
+	}
+
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
+			0xFF, driving[drive_sel][0]);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
+			0xFF, driving[drive_sel][1]);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
+			0xFF, driving[drive_sel][2]);
+}
+
+static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+	u32 reg;
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+	if (!rtsx_vendor_setting_valid(reg))
+		return;
+
+	pcr->aspm_en = rtsx_reg_to_aspm(reg);
+	pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
+	pcr->card_drive_sel &= 0x3F;
+	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+	pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
+	if (rtsx_reg_check_reverse_socket(reg))
+		pcr->flags |= PCR_REVERSE_SOCKET;
+}
+
+static void rts5227_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+	/* Set relink_time to 0 */
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0);
+
+	if (pm_state == HOST_ENTER_S3)
+		rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x10);
+
+	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
+}
+
+static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	u16 cap;
+
+	rtsx_pci_init_cmd(pcr);
+
+	/* Configure GPIO as output */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+	/* Reset ASPM state to default value */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
+	/* Switch LDO3318 source from DV33 to card_3v3 */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
+	/* LED shine disabled, set initial shine cycle period */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
+	/* Configure LTR */
+	pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cap);
+	if (cap & PCI_EXP_DEVCTL2_LTR_EN)
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3);
+	/* Configure OBFF */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03);
+	/* Configure driving */
+	rts5227_fill_driving(pcr, OUTPUT_3V3);
+	/* Configure force_clock_req */
+	if (pcr->flags & PCR_REVERSE_SOCKET)
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0xB8);
+	else
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0x88);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, pcr->reg_pm_ctrl3, 0x10, 0x00);
+
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
+{
+	int err;
+
+	err = rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00);
+	if (err < 0)
+		return err;
+
+	/* Optimize RX sensitivity */
+	return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
+}
+
+static int rts5227_turn_on_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
+}
+
+static int rts5227_turn_off_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
+}
+
+static int rts5227_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
+}
+
+static int rts5227_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
+}
+
+static int rts5227_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+	int err;
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK, SD_PARTIAL_POWER_ON);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x02);
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	/* To avoid too large in-rush current */
+	udelay(150);
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK, SD_POWER_ON);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x06);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK | PMOS_STRG_MASK,
+			SD_POWER_OFF | PMOS_STRG_400mA);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0X00);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	int err;
+
+	if (voltage == OUTPUT_3V3) {
+		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
+		if (err < 0)
+			return err;
+	} else if (voltage == OUTPUT_1V8) {
+		err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02);
+		if (err < 0)
+			return err;
+		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24);
+		if (err < 0)
+			return err;
+	} else {
+		return -EINVAL;
+	}
+
+	/* set pad drive */
+	rtsx_pci_init_cmd(pcr);
+	rts5227_fill_driving(pcr, voltage);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static const struct pcr_ops rts5227_pcr_ops = {
+	.fetch_vendor_settings = rts5227_fetch_vendor_settings,
+	.extra_init_hw = rts5227_extra_init_hw,
+	.optimize_phy = rts5227_optimize_phy,
+	.turn_on_led = rts5227_turn_on_led,
+	.turn_off_led = rts5227_turn_off_led,
+	.enable_auto_blink = rts5227_enable_auto_blink,
+	.disable_auto_blink = rts5227_disable_auto_blink,
+	.card_power_on = rts5227_card_power_on,
+	.card_power_off = rts5227_card_power_off,
+	.switch_output_voltage = rts5227_switch_output_voltage,
+	.cd_deglitch = NULL,
+	.conv_clk_and_div_n = NULL,
+	.force_power_down = rts5227_force_power_down,
+};
+
+/* SD Pull Control Enable:
+ *     SD_DAT[3:0] ==> pull up
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull up
+ *     SD_CMD      ==> pull up
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5227_sd_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
+	0,
+};
+
+/* SD Pull Control Disable:
+ *     SD_DAT[3:0] ==> pull down
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull down
+ *     SD_CMD      ==> pull down
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5227_sd_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
+	0,
+};
+
+/* MS Pull Control Enable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5227_ms_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+/* MS Pull Control Disable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5227_ms_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+void rts5227_init_params(struct rtsx_pcr *pcr)
+{
+	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+	pcr->num_slots = 2;
+	pcr->ops = &rts5227_pcr_ops;
+
+	pcr->flags = 0;
+	pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
+	pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
+	pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
+	pcr->aspm_en = ASPM_L1_EN;
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15);
+	pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 7, 7);
+
+	pcr->ic_version = rts5227_get_ic_version(pcr);
+	pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl;
+	pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl;
+	pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl;
+	pcr->ms_pull_ctl_disable_tbl = rts5227_ms_pull_ctl_disable_tbl;
+
+	pcr->reg_pm_ctrl3 = PM_CTRL3;
+}
+
+static int rts522a_optimize_phy(struct rtsx_pcr *pcr)
+{
+	int err;
+
+	err = rtsx_pci_write_register(pcr, RTS522A_PM_CTRL3, D3_DELINK_MODE_EN,
+		0x00);
+	if (err < 0)
+		return err;
+
+	if (is_version(pcr, 0x522A, IC_VER_A)) {
+		err = rtsx_pci_write_phy_register(pcr, PHY_RCR2,
+			PHY_RCR2_INIT_27S);
+		if (err)
+			return err;
+
+		rtsx_pci_write_phy_register(pcr, PHY_RCR1, PHY_RCR1_INIT_27S);
+		rtsx_pci_write_phy_register(pcr, PHY_FLD0, PHY_FLD0_INIT_27S);
+		rtsx_pci_write_phy_register(pcr, PHY_FLD3, PHY_FLD3_INIT_27S);
+		rtsx_pci_write_phy_register(pcr, PHY_FLD4, PHY_FLD4_INIT_27S);
+	}
+
+	return 0;
+}
+
+static int rts522a_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	rts5227_extra_init_hw(pcr);
+
+	rtsx_pci_write_register(pcr, FUNC_FORCE_CTL, FUNC_FORCE_UPME_XMT_DBG,
+		FUNC_FORCE_UPME_XMT_DBG);
+	rtsx_pci_write_register(pcr, PCLK_CTL, 0x04, 0x04);
+	rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0);
+	rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 0xFF, 0x11);
+
+	return 0;
+}
+
+/* rts522a operations mainly derived from rts5227, except phy/hw init setting.
+ */
+static const struct pcr_ops rts522a_pcr_ops = {
+	.fetch_vendor_settings = rts5227_fetch_vendor_settings,
+	.extra_init_hw = rts522a_extra_init_hw,
+	.optimize_phy = rts522a_optimize_phy,
+	.turn_on_led = rts5227_turn_on_led,
+	.turn_off_led = rts5227_turn_off_led,
+	.enable_auto_blink = rts5227_enable_auto_blink,
+	.disable_auto_blink = rts5227_disable_auto_blink,
+	.card_power_on = rts5227_card_power_on,
+	.card_power_off = rts5227_card_power_off,
+	.switch_output_voltage = rts5227_switch_output_voltage,
+	.cd_deglitch = NULL,
+	.conv_clk_and_div_n = NULL,
+	.force_power_down = rts5227_force_power_down,
+};
+
+void rts522a_init_params(struct rtsx_pcr *pcr)
+{
+	rts5227_init_params(pcr);
+
+	pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
+}
diff --git a/drivers/misc/cardreader/rts5229.c b/drivers/misc/cardreader/rts5229.c
new file mode 100644
index 0000000..9119261
--- /dev/null
+++ b/drivers/misc/cardreader/rts5229.c
@@ -0,0 +1,273 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/rtsx_pci.h>
+
+#include "rtsx_pcr.h"
+
+static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr)
+{
+	u8 val;
+
+	rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
+	return val & 0x0F;
+}
+
+static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+	u32 reg;
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+	if (!rtsx_vendor_setting_valid(reg))
+		return;
+
+	pcr->aspm_en = rtsx_reg_to_aspm(reg);
+	pcr->sd30_drive_sel_1v8 =
+		map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg));
+	pcr->card_drive_sel &= 0x3F;
+	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+	pcr->sd30_drive_sel_3v3 =
+		map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
+}
+
+static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
+}
+
+static int rts5229_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	rtsx_pci_init_cmd(pcr);
+
+	/* Configure GPIO as output */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+	/* Reset ASPM state to default value */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
+	/* Force CLKREQ# PIN to drive 0 to request clock */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
+	/* Switch LDO3318 source from DV33 to card_3v3 */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
+	/* LED shine disabled, set initial shine cycle period */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
+	/* Configure driving */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+			0xFF, pcr->sd30_drive_sel_3v3);
+
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5229_optimize_phy(struct rtsx_pcr *pcr)
+{
+	/* Optimize RX sensitivity */
+	return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
+}
+
+static int rts5229_turn_on_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
+}
+
+static int rts5229_turn_off_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
+}
+
+static int rts5229_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
+}
+
+static int rts5229_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
+}
+
+static int rts5229_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+	int err;
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK, SD_PARTIAL_POWER_ON);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x02);
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	/* To avoid too large in-rush current */
+	udelay(150);
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK, SD_POWER_ON);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x06);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK | PMOS_STRG_MASK,
+			SD_POWER_OFF | PMOS_STRG_400mA);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x00);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	int err;
+
+	if (voltage == OUTPUT_3V3) {
+		err = rtsx_pci_write_register(pcr,
+				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
+		if (err < 0)
+			return err;
+		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
+		if (err < 0)
+			return err;
+	} else if (voltage == OUTPUT_1V8) {
+		err = rtsx_pci_write_register(pcr,
+				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
+		if (err < 0)
+			return err;
+		err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
+		if (err < 0)
+			return err;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct pcr_ops rts5229_pcr_ops = {
+	.fetch_vendor_settings = rts5229_fetch_vendor_settings,
+	.extra_init_hw = rts5229_extra_init_hw,
+	.optimize_phy = rts5229_optimize_phy,
+	.turn_on_led = rts5229_turn_on_led,
+	.turn_off_led = rts5229_turn_off_led,
+	.enable_auto_blink = rts5229_enable_auto_blink,
+	.disable_auto_blink = rts5229_disable_auto_blink,
+	.card_power_on = rts5229_card_power_on,
+	.card_power_off = rts5229_card_power_off,
+	.switch_output_voltage = rts5229_switch_output_voltage,
+	.cd_deglitch = NULL,
+	.conv_clk_and_div_n = NULL,
+	.force_power_down = rts5229_force_power_down,
+};
+
+/* SD Pull Control Enable:
+ *     SD_DAT[3:0] ==> pull up
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull up
+ *     SD_CMD      ==> pull up
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5229_sd_pull_ctl_enable_tbl1[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
+	0,
+};
+
+/* For RTS5229 version C */
+static const u32 rts5229_sd_pull_ctl_enable_tbl2[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9),
+	0,
+};
+
+/* SD Pull Control Disable:
+ *     SD_DAT[3:0] ==> pull down
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull down
+ *     SD_CMD      ==> pull down
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5229_sd_pull_ctl_disable_tbl1[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
+	0,
+};
+
+/* For RTS5229 version C */
+static const u32 rts5229_sd_pull_ctl_disable_tbl2[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5),
+	0,
+};
+
+/* MS Pull Control Enable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5229_ms_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+/* MS Pull Control Disable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5229_ms_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+void rts5229_init_params(struct rtsx_pcr *pcr)
+{
+	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+	pcr->num_slots = 2;
+	pcr->ops = &rts5229_pcr_ops;
+
+	pcr->flags = 0;
+	pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
+	pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
+	pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
+	pcr->aspm_en = ASPM_L1_EN;
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15);
+	pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6);
+
+	pcr->ic_version = rts5229_get_ic_version(pcr);
+	if (pcr->ic_version == IC_VER_C) {
+		pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2;
+		pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2;
+	} else {
+		pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1;
+		pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1;
+	}
+	pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl;
+	pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl;
+}
diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c
new file mode 100644
index 0000000..dbe013a
--- /dev/null
+++ b/drivers/misc/cardreader/rts5249.c
@@ -0,0 +1,740 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/rtsx_pci.h>
+
+#include "rtsx_pcr.h"
+
+static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr)
+{
+	u8 val;
+
+	rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
+	return val & 0x0F;
+}
+
+static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
+{
+	u8 driving_3v3[4][3] = {
+		{0x11, 0x11, 0x18},
+		{0x55, 0x55, 0x5C},
+		{0xFF, 0xFF, 0xFF},
+		{0x96, 0x96, 0x96},
+	};
+	u8 driving_1v8[4][3] = {
+		{0xC4, 0xC4, 0xC4},
+		{0x3C, 0x3C, 0x3C},
+		{0xFE, 0xFE, 0xFE},
+		{0xB3, 0xB3, 0xB3},
+	};
+	u8 (*driving)[3], drive_sel;
+
+	if (voltage == OUTPUT_3V3) {
+		driving = driving_3v3;
+		drive_sel = pcr->sd30_drive_sel_3v3;
+	} else {
+		driving = driving_1v8;
+		drive_sel = pcr->sd30_drive_sel_1v8;
+	}
+
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
+			0xFF, driving[drive_sel][0]);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
+			0xFF, driving[drive_sel][1]);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
+			0xFF, driving[drive_sel][2]);
+}
+
+static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+	u32 reg;
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+	if (!rtsx_vendor_setting_valid(reg)) {
+		pcr_dbg(pcr, "skip fetch vendor setting\n");
+		return;
+	}
+
+	pcr->aspm_en = rtsx_reg_to_aspm(reg);
+	pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
+	pcr->card_drive_sel &= 0x3F;
+	pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
+
+	rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+	pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+	pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
+	if (rtsx_reg_check_reverse_socket(reg))
+		pcr->flags |= PCR_REVERSE_SOCKET;
+}
+
+static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+	/* Set relink_time to 0 */
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0);
+	rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0);
+
+	if (pm_state == HOST_ENTER_S3)
+		rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
+			D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+	rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
+}
+
+static void rts5249_init_from_cfg(struct rtsx_pcr *pcr)
+{
+	struct rtsx_cr_option *option = &(pcr->option);
+	u32 lval;
+
+	if (CHK_PCI_PID(pcr, PID_524A))
+		rtsx_pci_read_config_dword(pcr,
+			PCR_ASPM_SETTING_REG1, &lval);
+	else
+		rtsx_pci_read_config_dword(pcr,
+			PCR_ASPM_SETTING_REG2, &lval);
+
+	if (lval & ASPM_L1_1_EN_MASK)
+		rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
+
+	if (lval & ASPM_L1_2_EN_MASK)
+		rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
+
+	if (lval & PM_L1_1_EN_MASK)
+		rtsx_set_dev_flag(pcr, PM_L1_1_EN);
+
+	if (lval & PM_L1_2_EN_MASK)
+		rtsx_set_dev_flag(pcr, PM_L1_2_EN);
+
+	if (option->ltr_en) {
+		u16 val;
+
+		pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
+		if (val & PCI_EXP_DEVCTL2_LTR_EN) {
+			option->ltr_enabled = true;
+			option->ltr_active = true;
+			rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
+		} else {
+			option->ltr_enabled = false;
+		}
+	}
+}
+
+static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
+{
+	struct rtsx_cr_option *option = &(pcr->option);
+
+	if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
+				| PM_L1_1_EN | PM_L1_2_EN))
+		option->force_clkreq_0 = false;
+	else
+		option->force_clkreq_0 = true;
+
+	return 0;
+}
+
+static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	struct rtsx_cr_option *option = &(pcr->option);
+
+	rts5249_init_from_cfg(pcr);
+	rts5249_init_from_hw(pcr);
+
+	rtsx_pci_init_cmd(pcr);
+
+	/* Rest L1SUB Config */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, L1SUB_CONFIG3, 0xFF, 0x00);
+	/* Configure GPIO as output */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+	/* Reset ASPM state to default value */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
+	/* Switch LDO3318 source from DV33 to card_3v3 */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
+	/* LED shine disabled, set initial shine cycle period */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
+	/* Configure driving */
+	rts5249_fill_driving(pcr, OUTPUT_3V3);
+	if (pcr->flags & PCR_REVERSE_SOCKET)
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0xB0);
+	else
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80);
+
+	/*
+	 * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
+	 * to drive low, and we forcibly request clock.
+	 */
+	if (option->force_clkreq_0)
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
+			FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
+	else
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
+			FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
+
+	return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
+}
+
+static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
+{
+	int err;
+
+	err = rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00);
+	if (err < 0)
+		return err;
+
+	err = rtsx_pci_write_phy_register(pcr, PHY_REV,
+			PHY_REV_RESV | PHY_REV_RXIDLE_LATCHED |
+			PHY_REV_P1_EN | PHY_REV_RXIDLE_EN |
+			PHY_REV_CLKREQ_TX_EN | PHY_REV_RX_PWST |
+			PHY_REV_CLKREQ_DT_1_0 | PHY_REV_STOP_CLKRD |
+			PHY_REV_STOP_CLKWR);
+	if (err < 0)
+		return err;
+
+	msleep(1);
+
+	err = rtsx_pci_write_phy_register(pcr, PHY_BPCR,
+			PHY_BPCR_IBRXSEL | PHY_BPCR_IBTXSEL |
+			PHY_BPCR_IB_FILTER | PHY_BPCR_CMIRROR_EN);
+	if (err < 0)
+		return err;
+
+	err = rtsx_pci_write_phy_register(pcr, PHY_PCR,
+			PHY_PCR_FORCE_CODE | PHY_PCR_OOBS_CALI_50 |
+			PHY_PCR_OOBS_VCM_08 | PHY_PCR_OOBS_SEN_90 |
+			PHY_PCR_RSSI_EN | PHY_PCR_RX10K);
+	if (err < 0)
+		return err;
+
+	err = rtsx_pci_write_phy_register(pcr, PHY_RCR2,
+			PHY_RCR2_EMPHASE_EN | PHY_RCR2_NADJR |
+			PHY_RCR2_CDR_SR_2 | PHY_RCR2_FREQSEL_12 |
+			PHY_RCR2_CDR_SC_12P | PHY_RCR2_CALIB_LATE);
+	if (err < 0)
+		return err;
+
+	err = rtsx_pci_write_phy_register(pcr, PHY_FLD4,
+			PHY_FLD4_FLDEN_SEL | PHY_FLD4_REQ_REF |
+			PHY_FLD4_RXAMP_OFF | PHY_FLD4_REQ_ADDA |
+			PHY_FLD4_BER_COUNT | PHY_FLD4_BER_TIMER |
+			PHY_FLD4_BER_CHK_EN);
+	if (err < 0)
+		return err;
+	err = rtsx_pci_write_phy_register(pcr, PHY_RDR,
+			PHY_RDR_RXDSEL_1_9 | PHY_SSC_AUTO_PWD);
+	if (err < 0)
+		return err;
+	err = rtsx_pci_write_phy_register(pcr, PHY_RCR1,
+			PHY_RCR1_ADP_TIME_4 | PHY_RCR1_VCO_COARSE);
+	if (err < 0)
+		return err;
+	err = rtsx_pci_write_phy_register(pcr, PHY_FLD3,
+			PHY_FLD3_TIMER_4 | PHY_FLD3_TIMER_6 |
+			PHY_FLD3_RXDELINK);
+	if (err < 0)
+		return err;
+
+	return rtsx_pci_write_phy_register(pcr, PHY_TUNE,
+			PHY_TUNE_TUNEREF_1_0 | PHY_TUNE_VBGSEL_1252 |
+			PHY_TUNE_SDBUS_33 | PHY_TUNE_TUNED18 |
+			PHY_TUNE_TUNED12 | PHY_TUNE_TUNEA12);
+}
+
+static int rtsx_base_turn_on_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
+}
+
+static int rtsx_base_turn_off_led(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
+}
+
+static int rtsx_base_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
+}
+
+static int rtsx_base_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+	return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
+}
+
+static int rtsx_base_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+	int err;
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x02);
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	msleep(5);
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK, SD_VCC_POWER_ON);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x06);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rtsx_base_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+			SD_POWER_MASK, SD_POWER_OFF);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+			LDO3318_PWR_MASK, 0x00);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rtsx_base_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	int err;
+	u16 append;
+
+	switch (voltage) {
+	case OUTPUT_3V3:
+		err = rtsx_pci_update_phy(pcr, PHY_TUNE, PHY_TUNE_VOLTAGE_MASK,
+			PHY_TUNE_VOLTAGE_3V3);
+		if (err < 0)
+			return err;
+		break;
+	case OUTPUT_1V8:
+		append = PHY_TUNE_D18_1V8;
+		if (CHK_PCI_PID(pcr, 0x5249)) {
+			err = rtsx_pci_update_phy(pcr, PHY_BACR,
+				PHY_BACR_BASIC_MASK, 0);
+			if (err < 0)
+				return err;
+			append = PHY_TUNE_D18_1V7;
+		}
+
+		err = rtsx_pci_update_phy(pcr, PHY_TUNE, PHY_TUNE_VOLTAGE_MASK,
+			append);
+		if (err < 0)
+			return err;
+		break;
+	default:
+		pcr_dbg(pcr, "unknown output voltage %d\n", voltage);
+		return -EINVAL;
+	}
+
+	/* set pad drive */
+	rtsx_pci_init_cmd(pcr);
+	rts5249_fill_driving(pcr, voltage);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static void rts5249_set_aspm(struct rtsx_pcr *pcr, bool enable)
+{
+	struct rtsx_cr_option *option = &pcr->option;
+	u8 val = 0;
+
+	if (pcr->aspm_enabled == enable)
+		return;
+
+	if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
+		if (enable)
+			val = pcr->aspm_en;
+		rtsx_pci_update_cfg_byte(pcr,
+			pcr->pcie_cap + PCI_EXP_LNKCTL,
+			ASPM_MASK_NEG, val);
+	} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
+		u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0;
+
+		if (!enable)
+			val = FORCE_ASPM_CTL0;
+		rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
+	}
+
+	pcr->aspm_enabled = enable;
+}
+
+static const struct pcr_ops rts5249_pcr_ops = {
+	.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
+	.extra_init_hw = rts5249_extra_init_hw,
+	.optimize_phy = rts5249_optimize_phy,
+	.turn_on_led = rtsx_base_turn_on_led,
+	.turn_off_led = rtsx_base_turn_off_led,
+	.enable_auto_blink = rtsx_base_enable_auto_blink,
+	.disable_auto_blink = rtsx_base_disable_auto_blink,
+	.card_power_on = rtsx_base_card_power_on,
+	.card_power_off = rtsx_base_card_power_off,
+	.switch_output_voltage = rtsx_base_switch_output_voltage,
+	.force_power_down = rtsx_base_force_power_down,
+	.set_aspm = rts5249_set_aspm,
+};
+
+/* SD Pull Control Enable:
+ *     SD_DAT[3:0] ==> pull up
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull up
+ *     SD_CMD      ==> pull up
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5249_sd_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA),
+	0,
+};
+
+/* SD Pull Control Disable:
+ *     SD_DAT[3:0] ==> pull down
+ *     SD_CD       ==> pull up
+ *     SD_WP       ==> pull down
+ *     SD_CMD      ==> pull down
+ *     SD_CLK      ==> pull down
+ */
+static const u32 rts5249_sd_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
+	RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
+	0,
+};
+
+/* MS Pull Control Enable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5249_ms_pull_ctl_enable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+/* MS Pull Control Disable:
+ *     MS CD       ==> pull up
+ *     others      ==> pull down
+ */
+static const u32 rts5249_ms_pull_ctl_disable_tbl[] = {
+	RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+	RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+	0,
+};
+
+void rts5249_init_params(struct rtsx_pcr *pcr)
+{
+	struct rtsx_cr_option *option = &(pcr->option);
+
+	pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+	pcr->num_slots = 2;
+	pcr->ops = &rts5249_pcr_ops;
+
+	pcr->flags = 0;
+	pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
+	pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
+	pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
+	pcr->aspm_en = ASPM_L1_EN;
+	pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
+	pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
+
+	pcr->ic_version = rts5249_get_ic_version(pcr);
+	pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl;
+	pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl;
+	pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl;
+	pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl;
+
+	pcr->reg_pm_ctrl3 = PM_CTRL3;
+
+	option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
+				| LTR_L1SS_PWR_GATE_EN);
+	option->ltr_en = true;
+
+	/* Init latency of active, idle, L1OFF to 60us, 300us, 3ms */
+	option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
+	option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
+	option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
+	option->dev_aspm_mode = DEV_ASPM_DYNAMIC;
+	option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
+	option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5249_DEF;
+	option->ltr_l1off_snooze_sspwrgate =
+		LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF;
+}
+
+static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val)
+{
+	addr = addr & 0x80 ? (addr & 0x7F) | 0x40 : addr;
+
+	return __rtsx_pci_write_phy_register(pcr, addr, val);
+}
+
+static int rts524a_read_phy(struct rtsx_pcr *pcr, u8 addr, u16 *val)
+{
+	addr = addr & 0x80 ? (addr & 0x7F) | 0x40 : addr;
+
+	return __rtsx_pci_read_phy_register(pcr, addr, val);
+}
+
+static int rts524a_optimize_phy(struct rtsx_pcr *pcr)
+{
+	int err;
+
+	err = rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
+		D3_DELINK_MODE_EN, 0x00);
+	if (err < 0)
+		return err;
+
+	rtsx_pci_write_phy_register(pcr, PHY_PCR,
+		PHY_PCR_FORCE_CODE | PHY_PCR_OOBS_CALI_50 |
+		PHY_PCR_OOBS_VCM_08 | PHY_PCR_OOBS_SEN_90 | PHY_PCR_RSSI_EN);
+	rtsx_pci_write_phy_register(pcr, PHY_SSCCR3,
+		PHY_SSCCR3_STEP_IN | PHY_SSCCR3_CHECK_DELAY);
+
+	if (is_version(pcr, 0x524A, IC_VER_A)) {
+		rtsx_pci_write_phy_register(pcr, PHY_SSCCR3,
+			PHY_SSCCR3_STEP_IN | PHY_SSCCR3_CHECK_DELAY);
+		rtsx_pci_write_phy_register(pcr, PHY_SSCCR2,
+			PHY_SSCCR2_PLL_NCODE | PHY_SSCCR2_TIME0 |
+			PHY_SSCCR2_TIME2_WIDTH);
+		rtsx_pci_write_phy_register(pcr, PHY_ANA1A,
+			PHY_ANA1A_TXR_LOOPBACK | PHY_ANA1A_RXT_BIST |
+			PHY_ANA1A_TXR_BIST | PHY_ANA1A_REV);
+		rtsx_pci_write_phy_register(pcr, PHY_ANA1D,
+			PHY_ANA1D_DEBUG_ADDR);
+		rtsx_pci_write_phy_register(pcr, PHY_DIG1E,
+			PHY_DIG1E_REV | PHY_DIG1E_D0_X_D1 |
+			PHY_DIG1E_RX_ON_HOST | PHY_DIG1E_RCLK_REF_HOST |
+			PHY_DIG1E_RCLK_TX_EN_KEEP |
+			PHY_DIG1E_RCLK_TX_TERM_KEEP |
+			PHY_DIG1E_RCLK_RX_EIDLE_ON | PHY_DIG1E_TX_TERM_KEEP |
+			PHY_DIG1E_RX_TERM_KEEP | PHY_DIG1E_TX_EN_KEEP |
+			PHY_DIG1E_RX_EN_KEEP);
+	}
+
+	rtsx_pci_write_phy_register(pcr, PHY_ANA08,
+		PHY_ANA08_RX_EQ_DCGAIN | PHY_ANA08_SEL_RX_EN |
+		PHY_ANA08_RX_EQ_VAL | PHY_ANA08_SCP | PHY_ANA08_SEL_IPI);
+
+	return 0;
+}
+
+static int rts524a_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	rts5249_extra_init_hw(pcr);
+
+	rtsx_pci_write_register(pcr, FUNC_FORCE_CTL,
+		FORCE_ASPM_L1_EN, FORCE_ASPM_L1_EN);
+	rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0);
+	rtsx_pci_write_register(pcr, LDO_VCC_CFG1, LDO_VCC_LMT_EN,
+		LDO_VCC_LMT_EN);
+	rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL);
+	if (is_version(pcr, 0x524A, IC_VER_A)) {
+		rtsx_pci_write_register(pcr, LDO_DV18_CFG,
+			LDO_DV18_SR_MASK, LDO_DV18_SR_DF);
+		rtsx_pci_write_register(pcr, LDO_VCC_CFG1,
+			LDO_VCC_REF_TUNE_MASK, LDO_VCC_REF_1V2);
+		rtsx_pci_write_register(pcr, LDO_VIO_CFG,
+			LDO_VIO_REF_TUNE_MASK, LDO_VIO_REF_1V2);
+		rtsx_pci_write_register(pcr, LDO_VIO_CFG,
+			LDO_VIO_SR_MASK, LDO_VIO_SR_DF);
+		rtsx_pci_write_register(pcr, LDO_DV12S_CFG,
+			LDO_REF12_TUNE_MASK, LDO_REF12_TUNE_DF);
+		rtsx_pci_write_register(pcr, SD40_LDO_CTL1,
+			SD40_VIO_TUNE_MASK, SD40_VIO_TUNE_1V7);
+	}
+
+	return 0;
+}
+
+static void rts5250_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
+{
+	struct rtsx_cr_option *option = &(pcr->option);
+
+	u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR);
+	int card_exist = (interrupt & SD_EXIST) | (interrupt & MS_EXIST);
+	int aspm_L1_1, aspm_L1_2;
+	u8 val = 0;
+
+	aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
+	aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
+
+	if (active) {
+		/* Run, latency: 60us */
+		if (aspm_L1_1)
+			val = option->ltr_l1off_snooze_sspwrgate;
+	} else {
+		/* L1off, latency: 300us */
+		if (aspm_L1_2)
+			val = option->ltr_l1off_sspwrgate;
+	}
+
+	if (aspm_L1_1 || aspm_L1_2) {
+		if (rtsx_check_dev_flag(pcr,
+					LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) {
+			if (card_exist)
+				val &= ~L1OFF_MBIAS2_EN_5250;
+			else
+				val |= L1OFF_MBIAS2_EN_5250;
+		}
+	}
+	rtsx_set_l1off_sub(pcr, val);
+}
+
+static const struct pcr_ops rts524a_pcr_ops = {
+	.write_phy = rts524a_write_phy,
+	.read_phy = rts524a_read_phy,
+	.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
+	.extra_init_hw = rts524a_extra_init_hw,
+	.optimize_phy = rts524a_optimize_phy,
+	.turn_on_led = rtsx_base_turn_on_led,
+	.turn_off_led = rtsx_base_turn_off_led,
+	.enable_auto_blink = rtsx_base_enable_auto_blink,
+	.disable_auto_blink = rtsx_base_disable_auto_blink,
+	.card_power_on = rtsx_base_card_power_on,
+	.card_power_off = rtsx_base_card_power_off,
+	.switch_output_voltage = rtsx_base_switch_output_voltage,
+	.force_power_down = rtsx_base_force_power_down,
+	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
+	.set_aspm = rts5249_set_aspm,
+};
+
+void rts524a_init_params(struct rtsx_pcr *pcr)
+{
+	rts5249_init_params(pcr);
+	pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
+	pcr->option.ltr_l1off_snooze_sspwrgate =
+		LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
+
+	pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
+	pcr->ops = &rts524a_pcr_ops;
+}
+
+static int rts525a_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+	rtsx_pci_write_register(pcr, LDO_VCC_CFG1,
+		LDO_VCC_TUNE_MASK, LDO_VCC_3V3);
+	return rtsx_base_card_power_on(pcr, card);
+}
+
+static int rts525a_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	switch (voltage) {
+	case OUTPUT_3V3:
+		rtsx_pci_write_register(pcr, LDO_CONFIG2,
+			LDO_D3318_MASK, LDO_D3318_33V);
+		rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8, 0);
+		break;
+	case OUTPUT_1V8:
+		rtsx_pci_write_register(pcr, LDO_CONFIG2,
+			LDO_D3318_MASK, LDO_D3318_18V);
+		rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8,
+			SD_IO_USING_1V8);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rtsx_pci_init_cmd(pcr);
+	rts5249_fill_driving(pcr, voltage);
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts525a_optimize_phy(struct rtsx_pcr *pcr)
+{
+	int err;
+
+	err = rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
+		D3_DELINK_MODE_EN, 0x00);
+	if (err < 0)
+		return err;
+
+	rtsx_pci_write_phy_register(pcr, _PHY_FLD0,
+		_PHY_FLD0_CLK_REQ_20C | _PHY_FLD0_RX_IDLE_EN |
+		_PHY_FLD0_BIT_ERR_RSTN | _PHY_FLD0_BER_COUNT |
+		_PHY_FLD0_BER_TIMER | _PHY_FLD0_CHECK_EN);
+
+	rtsx_pci_write_phy_register(pcr, _PHY_ANA03,
+		_PHY_ANA03_TIMER_MAX | _PHY_ANA03_OOBS_DEB_EN |
+		_PHY_CMU_DEBUG_EN);
+
+	if (is_version(pcr, 0x525A, IC_VER_A))
+		rtsx_pci_write_phy_register(pcr, _PHY_REV0,
+			_PHY_REV0_FILTER_OUT | _PHY_REV0_CDR_BYPASS_PFD |
+			_PHY_REV0_CDR_RX_IDLE_BYPASS);
+
+	return 0;
+}
+
+static int rts525a_extra_init_hw(struct rtsx_pcr *pcr)
+{
+	rts5249_extra_init_hw(pcr);
+
+	rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL);
+	if (is_version(pcr, 0x525A, IC_VER_A)) {
+		rtsx_pci_write_register(pcr, L1SUB_CONFIG2,
+			L1SUB_AUTO_CFG, L1SUB_AUTO_CFG);
+		rtsx_pci_write_register(pcr, RREF_CFG,
+			RREF_VBGSEL_MASK, RREF_VBGSEL_1V25);
+		rtsx_pci_write_register(pcr, LDO_VIO_CFG,
+			LDO_VIO_TUNE_MASK, LDO_VIO_1V7);
+		rtsx_pci_write_register(pcr, LDO_DV12S_CFG,
+			LDO_D12_TUNE_MASK, LDO_D12_TUNE_DF);
+		rtsx_pci_write_register(pcr, LDO_AV12S_CFG,
+			LDO_AV12S_TUNE_MASK, LDO_AV12S_TUNE_DF);
+		rtsx_pci_write_register(pcr, LDO_VCC_CFG0,
+			LDO_VCC_LMTVTH_MASK, LDO_VCC_LMTVTH_2A);
+		rtsx_pci_write_register(pcr, OOBS_CONFIG,
+			OOBS_AUTOK_DIS | OOBS_VAL_MASK, 0x89);
+	}
+
+	return 0;
+}
+
+static const struct pcr_ops rts525a_pcr_ops = {
+	.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
+	.extra_init_hw = rts525a_extra_init_hw,
+	.optimize_phy = rts525a_optimize_phy,
+	.turn_on_led = rtsx_base_turn_on_led,
+	.turn_off_led = rtsx_base_turn_off_led,
+	.enable_auto_blink = rtsx_base_enable_auto_blink,
+	.disable_auto_blink = rtsx_base_disable_auto_blink,
+	.card_power_on = rts525a_card_power_on,
+	.card_power_off = rtsx_base_card_power_off,
+	.switch_output_voltage = rts525a_switch_output_voltage,
+	.force_power_down = rtsx_base_force_power_down,
+	.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
+	.set_aspm = rts5249_set_aspm,
+};
+
+void rts525a_init_params(struct rtsx_pcr *pcr)
+{
+	rts5249_init_params(pcr);
+	pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
+	pcr->option.ltr_l1off_snooze_sspwrgate =
+		LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
+
+	pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
+	pcr->ops = &rts525a_pcr_ops;
+}
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
new file mode 100644
index 0000000..c5430c2
--- /dev/null
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -0,0 +1,1572 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/rtsx_pci.h>
+#include <linux/mmc/card.h>
+#include <asm/unaligned.h>
+
+#include "rtsx_pcr.h"
+
+static bool msi_en = true;
+module_param(msi_en, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(msi_en, "Enable MSI");
+
+static DEFINE_IDR(rtsx_pci_idr);
+static DEFINE_SPINLOCK(rtsx_pci_lock);
+
+static struct mfd_cell rtsx_pcr_cells[] = {
+	[RTSX_SD_CARD] = {
+		.name = DRV_NAME_RTSX_PCI_SDMMC,
+	},
+	[RTSX_MS_CARD] = {
+		.name = DRV_NAME_RTSX_PCI_MS,
+	},
+};
+
+static const struct pci_device_id rtsx_pci_ids[] = {
+	{ PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x522A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x5286), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x524A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x525A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, rtsx_pci_ids);
+
+static inline void rtsx_pci_enable_aspm(struct rtsx_pcr *pcr)
+{
+	rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL,
+		0xFC, pcr->aspm_en);
+}
+
+static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr)
+{
+	rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL,
+		0xFC, 0);
+}
+
+int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
+{
+	rtsx_pci_write_register(pcr, MSGTXDATA0,
+				MASK_8_BIT_DEF, (u8) (latency & 0xFF));
+	rtsx_pci_write_register(pcr, MSGTXDATA1,
+				MASK_8_BIT_DEF, (u8)((latency >> 8) & 0xFF));
+	rtsx_pci_write_register(pcr, MSGTXDATA2,
+				MASK_8_BIT_DEF, (u8)((latency >> 16) & 0xFF));
+	rtsx_pci_write_register(pcr, MSGTXDATA3,
+				MASK_8_BIT_DEF, (u8)((latency >> 24) & 0xFF));
+	rtsx_pci_write_register(pcr, LTR_CTL, LTR_TX_EN_MASK |
+		LTR_LATENCY_MODE_MASK, LTR_TX_EN_1 | LTR_LATENCY_MODE_SW);
+
+	return 0;
+}
+
+int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
+{
+	if (pcr->ops->set_ltr_latency)
+		return pcr->ops->set_ltr_latency(pcr, latency);
+	else
+		return rtsx_comm_set_ltr_latency(pcr, latency);
+}
+
+static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable)
+{
+	struct rtsx_cr_option *option = &pcr->option;
+
+	if (pcr->aspm_enabled == enable)
+		return;
+
+	if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
+		if (enable)
+			rtsx_pci_enable_aspm(pcr);
+		else
+			rtsx_pci_disable_aspm(pcr);
+	} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
+		u8 mask = FORCE_ASPM_VAL_MASK;
+		u8 val = 0;
+
+		if (enable)
+			val = pcr->aspm_en;
+		rtsx_pci_write_register(pcr, ASPM_FORCE_CTL,  mask, val);
+	}
+
+	pcr->aspm_enabled = enable;
+}
+
+static void rtsx_disable_aspm(struct rtsx_pcr *pcr)
+{
+	if (pcr->ops->set_aspm)
+		pcr->ops->set_aspm(pcr, false);
+	else
+		rtsx_comm_set_aspm(pcr, false);
+}
+
+int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val)
+{
+	rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, val);
+
+	return 0;
+}
+
+void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active)
+{
+	if (pcr->ops->set_l1off_cfg_sub_d0)
+		pcr->ops->set_l1off_cfg_sub_d0(pcr, active);
+}
+
+static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr)
+{
+	struct rtsx_cr_option *option = &pcr->option;
+
+	rtsx_disable_aspm(pcr);
+
+	if (option->ltr_enabled)
+		rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
+
+	if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
+		rtsx_set_l1off_sub_cfg_d0(pcr, 1);
+}
+
+void rtsx_pm_full_on(struct rtsx_pcr *pcr)
+{
+	if (pcr->ops->full_on)
+		pcr->ops->full_on(pcr);
+	else
+		rtsx_comm_pm_full_on(pcr);
+}
+
+void rtsx_pci_start_run(struct rtsx_pcr *pcr)
+{
+	/* If pci device removed, don't queue idle work any more */
+	if (pcr->remove_pci)
+		return;
+
+	if (pcr->state != PDEV_STAT_RUN) {
+		pcr->state = PDEV_STAT_RUN;
+		if (pcr->ops->enable_auto_blink)
+			pcr->ops->enable_auto_blink(pcr);
+		rtsx_pm_full_on(pcr);
+	}
+
+	mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
+
+int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data)
+{
+	int i;
+	u32 val = HAIMR_WRITE_START;
+
+	val |= (u32)(addr & 0x3FFF) << 16;
+	val |= (u32)mask << 8;
+	val |= (u32)data;
+
+	rtsx_pci_writel(pcr, RTSX_HAIMR, val);
+
+	for (i = 0; i < MAX_RW_REG_CNT; i++) {
+		val = rtsx_pci_readl(pcr, RTSX_HAIMR);
+		if ((val & HAIMR_TRANS_END) == 0) {
+			if (data != (u8)val)
+				return -EIO;
+			return 0;
+		}
+	}
+
+	return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_write_register);
+
+int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data)
+{
+	u32 val = HAIMR_READ_START;
+	int i;
+
+	val |= (u32)(addr & 0x3FFF) << 16;
+	rtsx_pci_writel(pcr, RTSX_HAIMR, val);
+
+	for (i = 0; i < MAX_RW_REG_CNT; i++) {
+		val = rtsx_pci_readl(pcr, RTSX_HAIMR);
+		if ((val & HAIMR_TRANS_END) == 0)
+			break;
+	}
+
+	if (i >= MAX_RW_REG_CNT)
+		return -ETIMEDOUT;
+
+	if (data)
+		*data = (u8)(val & 0xFF);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_read_register);
+
+int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val)
+{
+	int err, i, finished = 0;
+	u8 tmp;
+
+	rtsx_pci_init_cmd(pcr);
+
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8));
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81);
+
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < 100000; i++) {
+		err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
+		if (err < 0)
+			return err;
+
+		if (!(tmp & 0x80)) {
+			finished = 1;
+			break;
+		}
+	}
+
+	if (!finished)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val)
+{
+	if (pcr->ops->write_phy)
+		return pcr->ops->write_phy(pcr, addr, val);
+
+	return __rtsx_pci_write_phy_register(pcr, addr, val);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_write_phy_register);
+
+int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
+{
+	int err, i, finished = 0;
+	u16 data;
+	u8 *ptr, tmp;
+
+	rtsx_pci_init_cmd(pcr);
+
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80);
+
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < 100000; i++) {
+		err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
+		if (err < 0)
+			return err;
+
+		if (!(tmp & 0x80)) {
+			finished = 1;
+			break;
+		}
+	}
+
+	if (!finished)
+		return -ETIMEDOUT;
+
+	rtsx_pci_init_cmd(pcr);
+
+	rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0);
+	rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0);
+
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	ptr = rtsx_pci_get_cmd_data(pcr);
+	data = ((u16)ptr[1] << 8) | ptr[0];
+
+	if (val)
+		*val = data;
+
+	return 0;
+}
+
+int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
+{
+	if (pcr->ops->read_phy)
+		return pcr->ops->read_phy(pcr, addr, val);
+
+	return __rtsx_pci_read_phy_register(pcr, addr, val);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register);
+
+void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr)
+{
+	rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
+	rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
+
+	rtsx_pci_write_register(pcr, DMACTL, 0x80, 0x80);
+	rtsx_pci_write_register(pcr, RBCTL, 0x80, 0x80);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_stop_cmd);
+
+void rtsx_pci_add_cmd(struct rtsx_pcr *pcr,
+		u8 cmd_type, u16 reg_addr, u8 mask, u8 data)
+{
+	unsigned long flags;
+	u32 val = 0;
+	u32 *ptr = (u32 *)(pcr->host_cmds_ptr);
+
+	val |= (u32)(cmd_type & 0x03) << 30;
+	val |= (u32)(reg_addr & 0x3FFF) << 16;
+	val |= (u32)mask << 8;
+	val |= (u32)data;
+
+	spin_lock_irqsave(&pcr->lock, flags);
+	ptr += pcr->ci;
+	if (pcr->ci < (HOST_CMDS_BUF_LEN / 4)) {
+		put_unaligned_le32(val, ptr);
+		ptr++;
+		pcr->ci++;
+	}
+	spin_unlock_irqrestore(&pcr->lock, flags);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_add_cmd);
+
+void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr)
+{
+	u32 val = 1 << 31;
+
+	rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
+
+	val |= (u32)(pcr->ci * 4) & 0x00FFFFFF;
+	/* Hardware Auto Response */
+	val |= 0x40000000;
+	rtsx_pci_writel(pcr, RTSX_HCBCTLR, val);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd_no_wait);
+
+int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout)
+{
+	struct completion trans_done;
+	u32 val = 1 << 31;
+	long timeleft;
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&pcr->lock, flags);
+
+	/* set up data structures for the wakeup system */
+	pcr->done = &trans_done;
+	pcr->trans_result = TRANS_NOT_READY;
+	init_completion(&trans_done);
+
+	rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
+
+	val |= (u32)(pcr->ci * 4) & 0x00FFFFFF;
+	/* Hardware Auto Response */
+	val |= 0x40000000;
+	rtsx_pci_writel(pcr, RTSX_HCBCTLR, val);
+
+	spin_unlock_irqrestore(&pcr->lock, flags);
+
+	/* Wait for TRANS_OK_INT */
+	timeleft = wait_for_completion_interruptible_timeout(
+			&trans_done, msecs_to_jiffies(timeout));
+	if (timeleft <= 0) {
+		pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__);
+		err = -ETIMEDOUT;
+		goto finish_send_cmd;
+	}
+
+	spin_lock_irqsave(&pcr->lock, flags);
+	if (pcr->trans_result == TRANS_RESULT_FAIL)
+		err = -EINVAL;
+	else if (pcr->trans_result == TRANS_RESULT_OK)
+		err = 0;
+	else if (pcr->trans_result == TRANS_NO_DEVICE)
+		err = -ENODEV;
+	spin_unlock_irqrestore(&pcr->lock, flags);
+
+finish_send_cmd:
+	spin_lock_irqsave(&pcr->lock, flags);
+	pcr->done = NULL;
+	spin_unlock_irqrestore(&pcr->lock, flags);
+
+	if ((err < 0) && (err != -ENODEV))
+		rtsx_pci_stop_cmd(pcr);
+
+	if (pcr->finish_me)
+		complete(pcr->finish_me);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd);
+
+static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
+		dma_addr_t addr, unsigned int len, int end)
+{
+	u64 *ptr = (u64 *)(pcr->host_sg_tbl_ptr) + pcr->sgi;
+	u64 val;
+	u8 option = SG_VALID | SG_TRANS_DATA;
+
+	pcr_dbg(pcr, "DMA addr: 0x%x, Len: 0x%x\n", (unsigned int)addr, len);
+
+	if (end)
+		option |= SG_END;
+	val = ((u64)addr << 32) | ((u64)len << 12) | option;
+
+	put_unaligned_le64(val, ptr);
+	pcr->sgi++;
+}
+
+int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int num_sg, bool read, int timeout)
+{
+	int err = 0, count;
+
+	pcr_dbg(pcr, "--> %s: num_sg = %d\n", __func__, num_sg);
+	count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
+	if (count < 1)
+		return -EINVAL;
+	pcr_dbg(pcr, "DMA mapping count: %d\n", count);
+
+	err = rtsx_pci_dma_transfer(pcr, sglist, count, read, timeout);
+
+	rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
+
+int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int num_sg, bool read)
+{
+	enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+	if (pcr->remove_pci)
+		return -EINVAL;
+
+	if ((sglist == NULL) || (num_sg <= 0))
+		return -EINVAL;
+
+	return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
+
+void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int num_sg, bool read)
+{
+	enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+	dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
+
+int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int count, bool read, int timeout)
+{
+	struct completion trans_done;
+	struct scatterlist *sg;
+	dma_addr_t addr;
+	long timeleft;
+	unsigned long flags;
+	unsigned int len;
+	int i, err = 0;
+	u32 val;
+	u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
+
+	if (pcr->remove_pci)
+		return -ENODEV;
+
+	if ((sglist == NULL) || (count < 1))
+		return -EINVAL;
+
+	val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
+	pcr->sgi = 0;
+	for_each_sg(sglist, sg, count, i) {
+		addr = sg_dma_address(sg);
+		len = sg_dma_len(sg);
+		rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
+	}
+
+	spin_lock_irqsave(&pcr->lock, flags);
+
+	pcr->done = &trans_done;
+	pcr->trans_result = TRANS_NOT_READY;
+	init_completion(&trans_done);
+	rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
+	rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
+
+	spin_unlock_irqrestore(&pcr->lock, flags);
+
+	timeleft = wait_for_completion_interruptible_timeout(
+			&trans_done, msecs_to_jiffies(timeout));
+	if (timeleft <= 0) {
+		pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__);
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	spin_lock_irqsave(&pcr->lock, flags);
+	if (pcr->trans_result == TRANS_RESULT_FAIL) {
+		err = -EILSEQ;
+		if (pcr->dma_error_count < RTS_MAX_TIMES_FREQ_REDUCTION)
+			pcr->dma_error_count++;
+	}
+
+	else if (pcr->trans_result == TRANS_NO_DEVICE)
+		err = -ENODEV;
+	spin_unlock_irqrestore(&pcr->lock, flags);
+
+out:
+	spin_lock_irqsave(&pcr->lock, flags);
+	pcr->done = NULL;
+	spin_unlock_irqrestore(&pcr->lock, flags);
+
+	if ((err < 0) && (err != -ENODEV))
+		rtsx_pci_stop_cmd(pcr);
+
+	if (pcr->finish_me)
+		complete(pcr->finish_me);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
+
+int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
+{
+	int err;
+	int i, j;
+	u16 reg;
+	u8 *ptr;
+
+	if (buf_len > 512)
+		buf_len = 512;
+
+	ptr = buf;
+	reg = PPBUF_BASE2;
+	for (i = 0; i < buf_len / 256; i++) {
+		rtsx_pci_init_cmd(pcr);
+
+		for (j = 0; j < 256; j++)
+			rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0);
+
+		err = rtsx_pci_send_cmd(pcr, 250);
+		if (err < 0)
+			return err;
+
+		memcpy(ptr, rtsx_pci_get_cmd_data(pcr), 256);
+		ptr += 256;
+	}
+
+	if (buf_len % 256) {
+		rtsx_pci_init_cmd(pcr);
+
+		for (j = 0; j < buf_len % 256; j++)
+			rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0);
+
+		err = rtsx_pci_send_cmd(pcr, 250);
+		if (err < 0)
+			return err;
+	}
+
+	memcpy(ptr, rtsx_pci_get_cmd_data(pcr), buf_len % 256);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_read_ppbuf);
+
+int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
+{
+	int err;
+	int i, j;
+	u16 reg;
+	u8 *ptr;
+
+	if (buf_len > 512)
+		buf_len = 512;
+
+	ptr = buf;
+	reg = PPBUF_BASE2;
+	for (i = 0; i < buf_len / 256; i++) {
+		rtsx_pci_init_cmd(pcr);
+
+		for (j = 0; j < 256; j++) {
+			rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+					reg++, 0xFF, *ptr);
+			ptr++;
+		}
+
+		err = rtsx_pci_send_cmd(pcr, 250);
+		if (err < 0)
+			return err;
+	}
+
+	if (buf_len % 256) {
+		rtsx_pci_init_cmd(pcr);
+
+		for (j = 0; j < buf_len % 256; j++) {
+			rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+					reg++, 0xFF, *ptr);
+			ptr++;
+		}
+
+		err = rtsx_pci_send_cmd(pcr, 250);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_write_ppbuf);
+
+static int rtsx_pci_set_pull_ctl(struct rtsx_pcr *pcr, const u32 *tbl)
+{
+	rtsx_pci_init_cmd(pcr);
+
+	while (*tbl & 0xFFFF0000) {
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+				(u16)(*tbl >> 16), 0xFF, (u8)(*tbl));
+		tbl++;
+	}
+
+	return rtsx_pci_send_cmd(pcr, 100);
+}
+
+int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card)
+{
+	const u32 *tbl;
+
+	if (card == RTSX_SD_CARD)
+		tbl = pcr->sd_pull_ctl_enable_tbl;
+	else if (card == RTSX_MS_CARD)
+		tbl = pcr->ms_pull_ctl_enable_tbl;
+	else
+		return -EINVAL;
+
+	return rtsx_pci_set_pull_ctl(pcr, tbl);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_enable);
+
+int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card)
+{
+	const u32 *tbl;
+
+	if (card == RTSX_SD_CARD)
+		tbl = pcr->sd_pull_ctl_disable_tbl;
+	else if (card == RTSX_MS_CARD)
+		tbl = pcr->ms_pull_ctl_disable_tbl;
+	else
+		return -EINVAL;
+
+
+	return rtsx_pci_set_pull_ctl(pcr, tbl);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_disable);
+
+static void rtsx_pci_enable_bus_int(struct rtsx_pcr *pcr)
+{
+	pcr->bier = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN | SD_INT_EN;
+
+	if (pcr->num_slots > 1)
+		pcr->bier |= MS_INT_EN;
+
+	/* Enable Bus Interrupt */
+	rtsx_pci_writel(pcr, RTSX_BIER, pcr->bier);
+
+	pcr_dbg(pcr, "RTSX_BIER: 0x%08x\n", pcr->bier);
+}
+
+static inline u8 double_ssc_depth(u8 depth)
+{
+	return ((depth > 1) ? (depth - 1) : depth);
+}
+
+static u8 revise_ssc_depth(u8 ssc_depth, u8 div)
+{
+	if (div > CLK_DIV_1) {
+		if (ssc_depth > (div - 1))
+			ssc_depth -= (div - 1);
+		else
+			ssc_depth = SSC_DEPTH_4M;
+	}
+
+	return ssc_depth;
+}
+
+int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
+		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
+{
+	int err, clk;
+	u8 n, clk_divider, mcu_cnt, div;
+	static const u8 depth[] = {
+		[RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M,
+		[RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M,
+		[RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M,
+		[RTSX_SSC_DEPTH_500K] = SSC_DEPTH_500K,
+		[RTSX_SSC_DEPTH_250K] = SSC_DEPTH_250K,
+	};
+
+	if (initial_mode) {
+		/* We use 250k(around) here, in initial stage */
+		clk_divider = SD_CLK_DIVIDE_128;
+		card_clock = 30000000;
+	} else {
+		clk_divider = SD_CLK_DIVIDE_0;
+	}
+	err = rtsx_pci_write_register(pcr, SD_CFG1,
+			SD_CLK_DIVIDE_MASK, clk_divider);
+	if (err < 0)
+		return err;
+
+	/* Reduce card clock by 20MHz each time a DMA transfer error occurs */
+	if (card_clock == UHS_SDR104_MAX_DTR &&
+	    pcr->dma_error_count &&
+	    PCI_PID(pcr) == RTS5227_DEVICE_ID)
+		card_clock = UHS_SDR104_MAX_DTR -
+			(pcr->dma_error_count * 20000000);
+
+	card_clock /= 1000000;
+	pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock);
+
+	clk = card_clock;
+	if (!initial_mode && double_clk)
+		clk = card_clock * 2;
+	pcr_dbg(pcr, "Internal SSC clock: %dMHz (cur_clock = %d)\n",
+		clk, pcr->cur_clock);
+
+	if (clk == pcr->cur_clock)
+		return 0;
+
+	if (pcr->ops->conv_clk_and_div_n)
+		n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
+	else
+		n = (u8)(clk - 2);
+	if ((clk <= 2) || (n > MAX_DIV_N_PCR))
+		return -EINVAL;
+
+	mcu_cnt = (u8)(125/clk + 3);
+	if (mcu_cnt > 15)
+		mcu_cnt = 15;
+
+	/* Make sure that the SSC clock div_n is not less than MIN_DIV_N_PCR */
+	div = CLK_DIV_1;
+	while ((n < MIN_DIV_N_PCR) && (div < CLK_DIV_8)) {
+		if (pcr->ops->conv_clk_and_div_n) {
+			int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
+					DIV_N_TO_CLK) * 2;
+			n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
+					CLK_TO_DIV_N);
+		} else {
+			n = (n + 2) * 2 - 2;
+		}
+		div++;
+	}
+	pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
+
+	ssc_depth = depth[ssc_depth];
+	if (double_clk)
+		ssc_depth = double_ssc_depth(ssc_depth);
+
+	ssc_depth = revise_ssc_depth(ssc_depth, div);
+	pcr_dbg(pcr, "ssc_depth = %d\n", ssc_depth);
+
+	rtsx_pci_init_cmd(pcr);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL,
+			CLK_LOW_FREQ, CLK_LOW_FREQ);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV,
+			0xFF, (div << 4) | mcu_cnt);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
+			SSC_DEPTH_MASK, ssc_depth);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
+	if (vpclk) {
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+				PHASE_NOT_RESET, 0);
+		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+				PHASE_NOT_RESET, PHASE_NOT_RESET);
+	}
+
+	err = rtsx_pci_send_cmd(pcr, 2000);
+	if (err < 0)
+		return err;
+
+	/* Wait SSC clock stable */
+	udelay(10);
+	err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
+	if (err < 0)
+		return err;
+
+	pcr->cur_clock = clk;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_switch_clock);
+
+int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+	if (pcr->ops->card_power_on)
+		return pcr->ops->card_power_on(pcr, card);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_power_on);
+
+int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+	if (pcr->ops->card_power_off)
+		return pcr->ops->card_power_off(pcr, card);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off);
+
+int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card)
+{
+	static const unsigned int cd_mask[] = {
+		[RTSX_SD_CARD] = SD_EXIST,
+		[RTSX_MS_CARD] = MS_EXIST
+	};
+
+	if (!(pcr->flags & PCR_MS_PMOS)) {
+		/* When using single PMOS, accessing card is not permitted
+		 * if the existing card is not the designated one.
+		 */
+		if (pcr->card_exist & (~cd_mask[card]))
+			return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_exclusive_check);
+
+int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	if (pcr->ops->switch_output_voltage)
+		return pcr->ops->switch_output_voltage(pcr, voltage);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_switch_output_voltage);
+
+unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr)
+{
+	unsigned int val;
+
+	val = rtsx_pci_readl(pcr, RTSX_BIPR);
+	if (pcr->ops->cd_deglitch)
+		val = pcr->ops->cd_deglitch(pcr);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_exist);
+
+void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr)
+{
+	struct completion finish;
+
+	pcr->finish_me = &finish;
+	init_completion(&finish);
+
+	if (pcr->done)
+		complete(pcr->done);
+
+	if (!pcr->remove_pci)
+		rtsx_pci_stop_cmd(pcr);
+
+	wait_for_completion_interruptible_timeout(&finish,
+			msecs_to_jiffies(2));
+	pcr->finish_me = NULL;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_complete_unfinished_transfer);
+
+static void rtsx_pci_card_detect(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct rtsx_pcr *pcr;
+	unsigned long flags;
+	unsigned int card_detect = 0, card_inserted, card_removed;
+	u32 irq_status;
+
+	dwork = to_delayed_work(work);
+	pcr = container_of(dwork, struct rtsx_pcr, carddet_work);
+
+	pcr_dbg(pcr, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+	spin_lock_irqsave(&pcr->lock, flags);
+
+	irq_status = rtsx_pci_readl(pcr, RTSX_BIPR);
+	pcr_dbg(pcr, "irq_status: 0x%08x\n", irq_status);
+
+	irq_status &= CARD_EXIST;
+	card_inserted = pcr->card_inserted & irq_status;
+	card_removed = pcr->card_removed;
+	pcr->card_inserted = 0;
+	pcr->card_removed = 0;
+
+	spin_unlock_irqrestore(&pcr->lock, flags);
+
+	if (card_inserted || card_removed) {
+		pcr_dbg(pcr, "card_inserted: 0x%x, card_removed: 0x%x\n",
+			card_inserted, card_removed);
+
+		if (pcr->ops->cd_deglitch)
+			card_inserted = pcr->ops->cd_deglitch(pcr);
+
+		card_detect = card_inserted | card_removed;
+
+		pcr->card_exist |= card_inserted;
+		pcr->card_exist &= ~card_removed;
+	}
+
+	mutex_unlock(&pcr->pcr_mutex);
+
+	if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event)
+		pcr->slots[RTSX_SD_CARD].card_event(
+				pcr->slots[RTSX_SD_CARD].p_dev);
+	if ((card_detect & MS_EXIST) && pcr->slots[RTSX_MS_CARD].card_event)
+		pcr->slots[RTSX_MS_CARD].card_event(
+				pcr->slots[RTSX_MS_CARD].p_dev);
+}
+
+static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
+{
+	struct rtsx_pcr *pcr = dev_id;
+	u32 int_reg;
+
+	if (!pcr)
+		return IRQ_NONE;
+
+	spin_lock(&pcr->lock);
+
+	int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
+	/* Clear interrupt flag */
+	rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
+	if ((int_reg & pcr->bier) == 0) {
+		spin_unlock(&pcr->lock);
+		return IRQ_NONE;
+	}
+	if (int_reg == 0xFFFFFFFF) {
+		spin_unlock(&pcr->lock);
+		return IRQ_HANDLED;
+	}
+
+	int_reg &= (pcr->bier | 0x7FFFFF);
+
+	if (int_reg & SD_INT) {
+		if (int_reg & SD_EXIST) {
+			pcr->card_inserted |= SD_EXIST;
+		} else {
+			pcr->card_removed |= SD_EXIST;
+			pcr->card_inserted &= ~SD_EXIST;
+		}
+		pcr->dma_error_count = 0;
+	}
+
+	if (int_reg & MS_INT) {
+		if (int_reg & MS_EXIST) {
+			pcr->card_inserted |= MS_EXIST;
+		} else {
+			pcr->card_removed |= MS_EXIST;
+			pcr->card_inserted &= ~MS_EXIST;
+		}
+	}
+
+	if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
+		if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
+			pcr->trans_result = TRANS_RESULT_FAIL;
+			if (pcr->done)
+				complete(pcr->done);
+		} else if (int_reg & TRANS_OK_INT) {
+			pcr->trans_result = TRANS_RESULT_OK;
+			if (pcr->done)
+				complete(pcr->done);
+		}
+	}
+
+	if (pcr->card_inserted || pcr->card_removed)
+		schedule_delayed_work(&pcr->carddet_work,
+				msecs_to_jiffies(200));
+
+	spin_unlock(&pcr->lock);
+	return IRQ_HANDLED;
+}
+
+static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr)
+{
+	pcr_dbg(pcr, "%s: pcr->msi_en = %d, pci->irq = %d\n",
+			__func__, pcr->msi_en, pcr->pci->irq);
+
+	if (request_irq(pcr->pci->irq, rtsx_pci_isr,
+			pcr->msi_en ? 0 : IRQF_SHARED,
+			DRV_NAME_RTSX_PCI, pcr)) {
+		dev_err(&(pcr->pci->dev),
+			"rtsx_sdmmc: unable to grab IRQ %d, disabling device\n",
+			pcr->pci->irq);
+		return -1;
+	}
+
+	pcr->irq = pcr->pci->irq;
+	pci_intx(pcr->pci, !pcr->msi_en);
+
+	return 0;
+}
+
+static void rtsx_enable_aspm(struct rtsx_pcr *pcr)
+{
+	if (pcr->ops->set_aspm)
+		pcr->ops->set_aspm(pcr, true);
+	else
+		rtsx_comm_set_aspm(pcr, true);
+}
+
+static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr)
+{
+	struct rtsx_cr_option *option = &pcr->option;
+
+	if (option->ltr_enabled) {
+		u32 latency = option->ltr_l1off_latency;
+
+		if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN))
+			mdelay(option->l1_snooze_delay);
+
+		rtsx_set_ltr_latency(pcr, latency);
+	}
+
+	if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
+		rtsx_set_l1off_sub_cfg_d0(pcr, 0);
+
+	rtsx_enable_aspm(pcr);
+}
+
+void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
+{
+	if (pcr->ops->power_saving)
+		pcr->ops->power_saving(pcr);
+	else
+		rtsx_comm_pm_power_saving(pcr);
+}
+
+static void rtsx_pci_idle_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
+
+	pcr_dbg(pcr, "--> %s\n", __func__);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pcr->state = PDEV_STAT_IDLE;
+
+	if (pcr->ops->disable_auto_blink)
+		pcr->ops->disable_auto_blink(pcr);
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pm_power_saving(pcr);
+
+	mutex_unlock(&pcr->pcr_mutex);
+}
+
+#ifdef CONFIG_PM
+static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+{
+	if (pcr->ops->turn_off_led)
+		pcr->ops->turn_off_led(pcr);
+
+	rtsx_pci_writel(pcr, RTSX_BIER, 0);
+	pcr->bier = 0;
+
+	rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08);
+	rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
+
+	if (pcr->ops->force_power_down)
+		pcr->ops->force_power_down(pcr, pm_state);
+}
+#endif
+
+static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
+{
+	int err;
+
+	pcr->pcie_cap = pci_find_capability(pcr->pci, PCI_CAP_ID_EXP);
+	rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
+
+	rtsx_pci_enable_bus_int(pcr);
+
+	/* Power on SSC */
+	err = rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, 0);
+	if (err < 0)
+		return err;
+
+	/* Wait SSC power stable */
+	udelay(200);
+
+	rtsx_pci_disable_aspm(pcr);
+	if (pcr->ops->optimize_phy) {
+		err = pcr->ops->optimize_phy(pcr);
+		if (err < 0)
+			return err;
+	}
+
+	rtsx_pci_init_cmd(pcr);
+
+	/* Set mcu_cnt to 7 to ensure data can be sampled properly */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, 0x07, 0x07);
+
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00);
+	/* Disable card clock */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0);
+	/* Reset delink mode */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0);
+	/* Card driving select */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL,
+			0xFF, pcr->card_drive_sel);
+	/* Enable SSC Clock */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1,
+			0xFF, SSC_8X_EN | SSC_SEL_4M);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12);
+	/* Disable cd_pwr_save */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x16, 0x10);
+	/* Clear Link Ready Interrupt */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0,
+			LINK_RDY_INT, LINK_RDY_INT);
+	/* Enlarge the estimation window of PERST# glitch
+	 * to reduce the chance of invalid card interrupt
+	 */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PERST_GLITCH_WIDTH, 0xFF, 0x80);
+	/* Update RC oscillator to 400k
+	 * bit[0] F_HIGH: for RC oscillator, Rst_value is 1'b1
+	 *                1: 2M  0: 400k
+	 */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RCCTL, 0x01, 0x00);
+	/* Set interrupt write clear
+	 * bit 1: U_elbi_if_rd_clr_en
+	 *	1: Enable ELBI interrupt[31:22] & [7:0] flag read clear
+	 *	0: ELBI interrupt flag[31:22] & [7:0] only can be write clear
+	 */
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0);
+
+	err = rtsx_pci_send_cmd(pcr, 100);
+	if (err < 0)
+		return err;
+
+	switch (PCI_PID(pcr)) {
+	case PID_5250:
+	case PID_524A:
+	case PID_525A:
+		rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
+		break;
+	default:
+		break;
+	}
+
+	/* Enable clk_request_n to enable clock power management */
+	rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1);
+	/* Enter L1 when host tx idle */
+	rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B);
+
+	if (pcr->ops->extra_init_hw) {
+		err = pcr->ops->extra_init_hw(pcr);
+		if (err < 0)
+			return err;
+	}
+
+	/* No CD interrupt if probing driver with card inserted.
+	 * So we need to initialize pcr->card_exist here.
+	 */
+	if (pcr->ops->cd_deglitch)
+		pcr->card_exist = pcr->ops->cd_deglitch(pcr);
+	else
+		pcr->card_exist = rtsx_pci_readl(pcr, RTSX_BIPR) & CARD_EXIST;
+
+	return 0;
+}
+
+static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
+{
+	int err;
+
+	spin_lock_init(&pcr->lock);
+	mutex_init(&pcr->pcr_mutex);
+
+	switch (PCI_PID(pcr)) {
+	default:
+	case 0x5209:
+		rts5209_init_params(pcr);
+		break;
+
+	case 0x5229:
+		rts5229_init_params(pcr);
+		break;
+
+	case 0x5289:
+		rtl8411_init_params(pcr);
+		break;
+
+	case 0x5227:
+		rts5227_init_params(pcr);
+		break;
+
+	case 0x522A:
+		rts522a_init_params(pcr);
+		break;
+
+	case 0x5249:
+		rts5249_init_params(pcr);
+		break;
+
+	case 0x524A:
+		rts524a_init_params(pcr);
+		break;
+
+	case 0x525A:
+		rts525a_init_params(pcr);
+		break;
+
+	case 0x5287:
+		rtl8411b_init_params(pcr);
+		break;
+
+	case 0x5286:
+		rtl8402_init_params(pcr);
+		break;
+	}
+
+	pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n",
+			PCI_PID(pcr), pcr->ic_version);
+
+	pcr->slots = kcalloc(pcr->num_slots, sizeof(struct rtsx_slot),
+			GFP_KERNEL);
+	if (!pcr->slots)
+		return -ENOMEM;
+
+	if (pcr->ops->fetch_vendor_settings)
+		pcr->ops->fetch_vendor_settings(pcr);
+
+	pcr_dbg(pcr, "pcr->aspm_en = 0x%x\n", pcr->aspm_en);
+	pcr_dbg(pcr, "pcr->sd30_drive_sel_1v8 = 0x%x\n",
+			pcr->sd30_drive_sel_1v8);
+	pcr_dbg(pcr, "pcr->sd30_drive_sel_3v3 = 0x%x\n",
+			pcr->sd30_drive_sel_3v3);
+	pcr_dbg(pcr, "pcr->card_drive_sel = 0x%x\n",
+			pcr->card_drive_sel);
+	pcr_dbg(pcr, "pcr->flags = 0x%x\n", pcr->flags);
+
+	pcr->state = PDEV_STAT_IDLE;
+	err = rtsx_pci_init_hw(pcr);
+	if (err < 0) {
+		kfree(pcr->slots);
+		return err;
+	}
+
+	return 0;
+}
+
+static int rtsx_pci_probe(struct pci_dev *pcidev,
+			  const struct pci_device_id *id)
+{
+	struct rtsx_pcr *pcr;
+	struct pcr_handle *handle;
+	u32 base, len;
+	int ret, i, bar = 0;
+
+	dev_dbg(&(pcidev->dev),
+		": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n",
+		pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device,
+		(int)pcidev->revision);
+
+	ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
+	if (ret < 0)
+		return ret;
+
+	ret = pci_enable_device(pcidev);
+	if (ret)
+		return ret;
+
+	ret = pci_request_regions(pcidev, DRV_NAME_RTSX_PCI);
+	if (ret)
+		goto disable;
+
+	pcr = kzalloc(sizeof(*pcr), GFP_KERNEL);
+	if (!pcr) {
+		ret = -ENOMEM;
+		goto release_pci;
+	}
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle) {
+		ret = -ENOMEM;
+		goto free_pcr;
+	}
+	handle->pcr = pcr;
+
+	idr_preload(GFP_KERNEL);
+	spin_lock(&rtsx_pci_lock);
+	ret = idr_alloc(&rtsx_pci_idr, pcr, 0, 0, GFP_NOWAIT);
+	if (ret >= 0)
+		pcr->id = ret;
+	spin_unlock(&rtsx_pci_lock);
+	idr_preload_end();
+	if (ret < 0)
+		goto free_handle;
+
+	pcr->pci = pcidev;
+	dev_set_drvdata(&pcidev->dev, handle);
+
+	if (CHK_PCI_PID(pcr, 0x525A))
+		bar = 1;
+	len = pci_resource_len(pcidev, bar);
+	base = pci_resource_start(pcidev, bar);
+	pcr->remap_addr = ioremap_nocache(base, len);
+	if (!pcr->remap_addr) {
+		ret = -ENOMEM;
+		goto free_handle;
+	}
+
+	pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev),
+			RTSX_RESV_BUF_LEN, &(pcr->rtsx_resv_buf_addr),
+			GFP_KERNEL);
+	if (pcr->rtsx_resv_buf == NULL) {
+		ret = -ENXIO;
+		goto unmap;
+	}
+	pcr->host_cmds_ptr = pcr->rtsx_resv_buf;
+	pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr;
+	pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN;
+	pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN;
+
+	pcr->card_inserted = 0;
+	pcr->card_removed = 0;
+	INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
+	INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
+
+	pcr->msi_en = msi_en;
+	if (pcr->msi_en) {
+		ret = pci_enable_msi(pcidev);
+		if (ret)
+			pcr->msi_en = false;
+	}
+
+	ret = rtsx_pci_acquire_irq(pcr);
+	if (ret < 0)
+		goto disable_msi;
+
+	pci_set_master(pcidev);
+	synchronize_irq(pcr->irq);
+
+	ret = rtsx_pci_init_chip(pcr);
+	if (ret < 0)
+		goto disable_irq;
+
+	for (i = 0; i < ARRAY_SIZE(rtsx_pcr_cells); i++) {
+		rtsx_pcr_cells[i].platform_data = handle;
+		rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
+	}
+	ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
+			ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
+	if (ret < 0)
+		goto disable_irq;
+
+	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+
+	return 0;
+
+disable_irq:
+	free_irq(pcr->irq, (void *)pcr);
+disable_msi:
+	if (pcr->msi_en)
+		pci_disable_msi(pcr->pci);
+	dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN,
+			pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr);
+unmap:
+	iounmap(pcr->remap_addr);
+free_handle:
+	kfree(handle);
+free_pcr:
+	kfree(pcr);
+release_pci:
+	pci_release_regions(pcidev);
+disable:
+	pci_disable_device(pcidev);
+
+	return ret;
+}
+
+static void rtsx_pci_remove(struct pci_dev *pcidev)
+{
+	struct pcr_handle *handle = pci_get_drvdata(pcidev);
+	struct rtsx_pcr *pcr = handle->pcr;
+
+	pcr->remove_pci = true;
+
+	/* Disable interrupts at the pcr level */
+	spin_lock_irq(&pcr->lock);
+	rtsx_pci_writel(pcr, RTSX_BIER, 0);
+	pcr->bier = 0;
+	spin_unlock_irq(&pcr->lock);
+
+	cancel_delayed_work_sync(&pcr->carddet_work);
+	cancel_delayed_work_sync(&pcr->idle_work);
+
+	mfd_remove_devices(&pcidev->dev);
+
+	dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN,
+			pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr);
+	free_irq(pcr->irq, (void *)pcr);
+	if (pcr->msi_en)
+		pci_disable_msi(pcr->pci);
+	iounmap(pcr->remap_addr);
+
+	pci_release_regions(pcidev);
+	pci_disable_device(pcidev);
+
+	spin_lock(&rtsx_pci_lock);
+	idr_remove(&rtsx_pci_idr, pcr->id);
+	spin_unlock(&rtsx_pci_lock);
+
+	kfree(pcr->slots);
+	kfree(pcr);
+	kfree(handle);
+
+	dev_dbg(&(pcidev->dev),
+		": Realtek PCI-E Card Reader at %s [%04x:%04x] has been removed\n",
+		pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
+}
+
+#ifdef CONFIG_PM
+
+static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
+{
+	struct pcr_handle *handle;
+	struct rtsx_pcr *pcr;
+
+	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+
+	handle = pci_get_drvdata(pcidev);
+	pcr = handle->pcr;
+
+	cancel_delayed_work(&pcr->carddet_work);
+	cancel_delayed_work(&pcr->idle_work);
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+
+	pci_save_state(pcidev);
+	pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
+	pci_disable_device(pcidev);
+	pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
+
+	mutex_unlock(&pcr->pcr_mutex);
+	return 0;
+}
+
+static int rtsx_pci_resume(struct pci_dev *pcidev)
+{
+	struct pcr_handle *handle;
+	struct rtsx_pcr *pcr;
+	int ret = 0;
+
+	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+
+	handle = pci_get_drvdata(pcidev);
+	pcr = handle->pcr;
+
+	mutex_lock(&pcr->pcr_mutex);
+
+	pci_set_power_state(pcidev, PCI_D0);
+	pci_restore_state(pcidev);
+	ret = pci_enable_device(pcidev);
+	if (ret)
+		goto out;
+	pci_set_master(pcidev);
+
+	ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
+	if (ret)
+		goto out;
+
+	ret = rtsx_pci_init_hw(pcr);
+	if (ret)
+		goto out;
+
+	schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+
+out:
+	mutex_unlock(&pcr->pcr_mutex);
+	return ret;
+}
+
+static void rtsx_pci_shutdown(struct pci_dev *pcidev)
+{
+	struct pcr_handle *handle;
+	struct rtsx_pcr *pcr;
+
+	dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+
+	handle = pci_get_drvdata(pcidev);
+	pcr = handle->pcr;
+	rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+
+	pci_disable_device(pcidev);
+	free_irq(pcr->irq, (void *)pcr);
+	if (pcr->msi_en)
+		pci_disable_msi(pcr->pci);
+}
+
+#else /* CONFIG_PM */
+
+#define rtsx_pci_suspend NULL
+#define rtsx_pci_resume NULL
+#define rtsx_pci_shutdown NULL
+
+#endif /* CONFIG_PM */
+
+static struct pci_driver rtsx_pci_driver = {
+	.name = DRV_NAME_RTSX_PCI,
+	.id_table = rtsx_pci_ids,
+	.probe = rtsx_pci_probe,
+	.remove = rtsx_pci_remove,
+	.suspend = rtsx_pci_suspend,
+	.resume = rtsx_pci_resume,
+	.shutdown = rtsx_pci_shutdown,
+};
+module_pci_driver(rtsx_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>");
+MODULE_DESCRIPTION("Realtek PCI-E Card Reader Driver");
diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h
new file mode 100644
index 0000000..b0691c9
--- /dev/null
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -0,0 +1,103 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ */
+
+#ifndef __RTSX_PCR_H
+#define __RTSX_PCR_H
+
+#include <linux/rtsx_pci.h>
+
+#define MIN_DIV_N_PCR		80
+#define MAX_DIV_N_PCR		208
+
+#define RTS522A_PM_CTRL3		0xFF7E
+
+#define RTS524A_PME_FORCE_CTL		0xFF78
+#define RTS524A_PM_CTRL3		0xFF7E
+
+#define LTR_ACTIVE_LATENCY_DEF		0x883C
+#define LTR_IDLE_LATENCY_DEF		0x892C
+#define LTR_L1OFF_LATENCY_DEF		0x9003
+#define L1_SNOOZE_DELAY_DEF		1
+#define LTR_L1OFF_SSPWRGATE_5249_DEF		0xAF
+#define LTR_L1OFF_SSPWRGATE_5250_DEF		0xFF
+#define LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF	0xAC
+#define LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF	0xF8
+#define CMD_TIMEOUT_DEF		100
+#define ASPM_MASK_NEG		0xFC
+#define MASK_8_BIT_DEF		0xFF
+
+int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
+int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
+
+void rts5209_init_params(struct rtsx_pcr *pcr);
+void rts5229_init_params(struct rtsx_pcr *pcr);
+void rtl8411_init_params(struct rtsx_pcr *pcr);
+void rtl8402_init_params(struct rtsx_pcr *pcr);
+void rts5227_init_params(struct rtsx_pcr *pcr);
+void rts522a_init_params(struct rtsx_pcr *pcr);
+void rts5249_init_params(struct rtsx_pcr *pcr);
+void rts524a_init_params(struct rtsx_pcr *pcr);
+void rts525a_init_params(struct rtsx_pcr *pcr);
+void rtl8411b_init_params(struct rtsx_pcr *pcr);
+
+static inline u8 map_sd_drive(int idx)
+{
+	u8 sd_drive[4] = {
+		0x01,	/* Type D */
+		0x02,	/* Type C */
+		0x05,	/* Type A */
+		0x03	/* Type B */
+	};
+
+	return sd_drive[idx];
+}
+
+#define rtsx_vendor_setting_valid(reg)		(!((reg) & 0x1000000))
+#define rts5209_vendor_setting1_valid(reg)	(!((reg) & 0x80))
+#define rts5209_vendor_setting2_valid(reg)	((reg) & 0x80)
+
+#define rtsx_reg_to_aspm(reg)			(((reg) >> 28) & 0x03)
+#define rtsx_reg_to_sd30_drive_sel_1v8(reg)	(((reg) >> 26) & 0x03)
+#define rtsx_reg_to_sd30_drive_sel_3v3(reg)	(((reg) >> 5) & 0x03)
+#define rtsx_reg_to_card_drive_sel(reg)		((((reg) >> 25) & 0x01) << 6)
+#define rtsx_reg_check_reverse_socket(reg)	((reg) & 0x4000)
+#define rts5209_reg_to_aspm(reg)		(((reg) >> 5) & 0x03)
+#define rts5209_reg_check_ms_pmos(reg)		(!((reg) & 0x08))
+#define rts5209_reg_to_sd30_drive_sel_1v8(reg)	(((reg) >> 3) & 0x07)
+#define rts5209_reg_to_sd30_drive_sel_3v3(reg)	((reg) & 0x07)
+#define rts5209_reg_to_card_drive_sel(reg)	((reg) >> 8)
+#define rtl8411_reg_to_sd30_drive_sel_3v3(reg)	(((reg) >> 5) & 0x07)
+#define rtl8411b_reg_to_sd30_drive_sel_3v3(reg)	((reg) & 0x03)
+
+#define set_pull_ctrl_tables(pcr, __device)				\
+do {									\
+	pcr->sd_pull_ctl_enable_tbl  = __device##_sd_pull_ctl_enable_tbl;  \
+	pcr->sd_pull_ctl_disable_tbl = __device##_sd_pull_ctl_disable_tbl; \
+	pcr->ms_pull_ctl_enable_tbl  = __device##_ms_pull_ctl_enable_tbl;  \
+	pcr->ms_pull_ctl_disable_tbl = __device##_ms_pull_ctl_disable_tbl; \
+} while (0)
+
+/* generic operations */
+int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
+int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency);
+int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val);
+
+#endif
diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c
new file mode 100644
index 0000000..b97903f
--- /dev/null
+++ b/drivers/misc/cardreader/rtsx_usb.c
@@ -0,0 +1,791 @@ 
+/* Driver for Realtek USB card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Roger Tseng <rogerable@realtek.com>
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/rtsx_usb.h>
+
+static int polling_pipe = 1;
+module_param(polling_pipe, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)");
+
+static const struct mfd_cell rtsx_usb_cells[] = {
+	[RTSX_USB_SD_CARD] = {
+		.name = "rtsx_usb_sdmmc",
+		.pdata_size = 0,
+	},
+	[RTSX_USB_MS_CARD] = {
+		.name = "rtsx_usb_ms",
+		.pdata_size = 0,
+	},
+};
+
+static void rtsx_usb_sg_timed_out(struct timer_list *t)
+{
+	struct rtsx_ucr *ucr = from_timer(ucr, t, sg_timer);
+
+	dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
+	usb_sg_cancel(&ucr->current_sg);
+}
+
+static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
+		unsigned int pipe, struct scatterlist *sg, int num_sg,
+		unsigned int length, unsigned int *act_len, int timeout)
+{
+	int ret;
+
+	dev_dbg(&ucr->pusb_intf->dev, "%s: xfer %u bytes, %d entries\n",
+			__func__, length, num_sg);
+	ret = usb_sg_init(&ucr->current_sg, ucr->pusb_dev, pipe, 0,
+			sg, num_sg, length, GFP_NOIO);
+	if (ret)
+		return ret;
+
+	ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
+	add_timer(&ucr->sg_timer);
+	usb_sg_wait(&ucr->current_sg);
+	if (!del_timer_sync(&ucr->sg_timer))
+		ret = -ETIMEDOUT;
+	else
+		ret = ucr->current_sg.status;
+
+	if (act_len)
+		*act_len = ucr->current_sg.bytes;
+
+	return ret;
+}
+
+int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
+			      void *buf, unsigned int len, int num_sg,
+			      unsigned int *act_len, int timeout)
+{
+	if (timeout < 600)
+		timeout = 600;
+
+	if (num_sg)
+		return rtsx_usb_bulk_transfer_sglist(ucr, pipe,
+				(struct scatterlist *)buf, num_sg, len, act_len,
+				timeout);
+	else
+		return usb_bulk_msg(ucr->pusb_dev, pipe, buf, len, act_len,
+				timeout);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_transfer_data);
+
+static inline void rtsx_usb_seq_cmd_hdr(struct rtsx_ucr *ucr,
+		u16 addr, u16 len, u8 seq_type)
+{
+	rtsx_usb_cmd_hdr_tag(ucr);
+
+	ucr->cmd_buf[PACKET_TYPE] = seq_type;
+	ucr->cmd_buf[5] = (u8)(len >> 8);
+	ucr->cmd_buf[6] = (u8)len;
+	ucr->cmd_buf[8] = (u8)(addr >> 8);
+	ucr->cmd_buf[9] = (u8)addr;
+
+	if (seq_type == SEQ_WRITE)
+		ucr->cmd_buf[STAGE_FLAG] = 0;
+	else
+		ucr->cmd_buf[STAGE_FLAG] = STAGE_R;
+}
+
+static int rtsx_usb_seq_write_register(struct rtsx_ucr *ucr,
+		u16 addr, u16 len, u8 *data)
+{
+	u16 cmd_len = ALIGN(SEQ_WRITE_DATA_OFFSET + len, 4);
+
+	if (!data)
+		return -EINVAL;
+
+	if (cmd_len > IOBUF_SIZE)
+		return -EINVAL;
+
+	rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_WRITE);
+	memcpy(ucr->cmd_buf + SEQ_WRITE_DATA_OFFSET, data, len);
+
+	return rtsx_usb_transfer_data(ucr,
+			usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
+			ucr->cmd_buf, cmd_len, 0, NULL, 100);
+}
+
+static int rtsx_usb_seq_read_register(struct rtsx_ucr *ucr,
+		u16 addr, u16 len, u8 *data)
+{
+	int i, ret;
+	u16 rsp_len = round_down(len, 4);
+	u16 res_len = len - rsp_len;
+
+	if (!data)
+		return -EINVAL;
+
+	/* 4-byte aligned part */
+	if (rsp_len) {
+		rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_READ);
+		ret = rtsx_usb_transfer_data(ucr,
+				usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
+				ucr->cmd_buf, 12, 0, NULL, 100);
+		if (ret)
+			return ret;
+
+		ret = rtsx_usb_transfer_data(ucr,
+				usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
+				data, rsp_len, 0, NULL, 100);
+		if (ret)
+			return ret;
+	}
+
+	/* unaligned part */
+	for (i = 0; i < res_len; i++) {
+		ret = rtsx_usb_read_register(ucr, addr + rsp_len + i,
+				data + rsp_len + i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
+{
+	return rtsx_usb_seq_read_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_read_ppbuf);
+
+int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
+{
+	return rtsx_usb_seq_write_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_write_ppbuf);
+
+int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr,
+		u8 mask, u8 data)
+{
+	u16 value, index;
+
+	addr |= EP0_WRITE_REG_CMD << EP0_OP_SHIFT;
+	value = swab16(addr);
+	index = mask | data << 8;
+
+	return usb_control_msg(ucr->pusb_dev,
+			usb_sndctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, index, NULL, 0, 100);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
+
+int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
+{
+	u16 value;
+	u8 *buf;
+	int ret;
+
+	if (!data)
+		return -EINVAL;
+
+	buf = kzalloc(sizeof(u8), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
+	value = swab16(addr);
+
+	ret = usb_control_msg(ucr->pusb_dev,
+			usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value, 0, buf, 1, 100);
+	*data = *buf;
+
+	kfree(buf);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
+
+void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type, u16 reg_addr,
+		u8 mask, u8 data)
+{
+	int i;
+
+	if (ucr->cmd_idx < (IOBUF_SIZE - CMD_OFFSET) / 4) {
+		i = CMD_OFFSET + ucr->cmd_idx * 4;
+
+		ucr->cmd_buf[i++] = ((cmd_type & 0x03) << 6) |
+			(u8)((reg_addr >> 8) & 0x3F);
+		ucr->cmd_buf[i++] = (u8)reg_addr;
+		ucr->cmd_buf[i++] = mask;
+		ucr->cmd_buf[i++] = data;
+
+		ucr->cmd_idx++;
+	}
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_add_cmd);
+
+int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout)
+{
+	int ret;
+
+	ucr->cmd_buf[CNT_H] = (u8)(ucr->cmd_idx >> 8);
+	ucr->cmd_buf[CNT_L] = (u8)(ucr->cmd_idx);
+	ucr->cmd_buf[STAGE_FLAG] = flag;
+
+	ret = rtsx_usb_transfer_data(ucr,
+			usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
+			ucr->cmd_buf, ucr->cmd_idx * 4 + CMD_OFFSET,
+			0, NULL, timeout);
+	if (ret) {
+		rtsx_usb_clear_fsm_err(ucr);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_send_cmd);
+
+int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout)
+{
+	if (rsp_len <= 0)
+		return -EINVAL;
+
+	rsp_len = ALIGN(rsp_len, 4);
+
+	return rtsx_usb_transfer_data(ucr,
+			usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
+			ucr->rsp_buf, rsp_len, 0, NULL, timeout);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_get_rsp);
+
+static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
+{
+	int ret;
+
+	rtsx_usb_init_cmd(ucr);
+	rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_EXIST, 0x00, 0x00);
+	rtsx_usb_add_cmd(ucr, READ_REG_CMD, OCPSTAT, 0x00, 0x00);
+	ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
+	if (ret)
+		return ret;
+
+	ret = rtsx_usb_get_rsp(ucr, 2, 100);
+	if (ret)
+		return ret;
+
+	*status = ((ucr->rsp_buf[0] >> 2) & 0x0f) |
+		  ((ucr->rsp_buf[1] & 0x03) << 4);
+
+	return 0;
+}
+
+int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
+{
+	int ret;
+	u16 *buf;
+
+	if (!status)
+		return -EINVAL;
+
+	if (polling_pipe == 0) {
+		buf = kzalloc(sizeof(u16), GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+
+		ret = usb_control_msg(ucr->pusb_dev,
+				usb_rcvctrlpipe(ucr->pusb_dev, 0),
+				RTSX_USB_REQ_POLL,
+				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				0, 0, buf, 2, 100);
+		*status = *buf;
+
+		kfree(buf);
+	} else {
+		ret = rtsx_usb_get_status_with_bulk(ucr, status);
+	}
+
+	/* usb_control_msg may return positive when success */
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_get_card_status);
+
+static int rtsx_usb_write_phy_register(struct rtsx_ucr *ucr, u8 addr, u8 val)
+{
+	dev_dbg(&ucr->pusb_intf->dev, "Write 0x%x to phy register 0x%x\n",
+			val, addr);
+
+	rtsx_usb_init_cmd(ucr);
+
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VSTAIN, 0xFF, val);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL,
+			0xFF, (addr >> 4) & 0x0F);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+
+	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+
+int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask, u8 data)
+{
+	rtsx_usb_init_cmd(ucr);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, addr, mask, data);
+	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_write_register);
+
+int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
+{
+	int ret;
+
+	if (data != NULL)
+		*data = 0;
+
+	rtsx_usb_init_cmd(ucr);
+	rtsx_usb_add_cmd(ucr, READ_REG_CMD, addr, 0, 0);
+	ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
+	if (ret)
+		return ret;
+
+	ret = rtsx_usb_get_rsp(ucr, 1, 100);
+	if (ret)
+		return ret;
+
+	if (data != NULL)
+		*data = ucr->rsp_buf[0];
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_read_register);
+
+static inline u8 double_ssc_depth(u8 depth)
+{
+	return (depth > 1) ? (depth - 1) : depth;
+}
+
+static u8 revise_ssc_depth(u8 ssc_depth, u8 div)
+{
+	if (div > CLK_DIV_1) {
+		if (ssc_depth > div - 1)
+			ssc_depth -= (div - 1);
+		else
+			ssc_depth = SSC_DEPTH_2M;
+	}
+
+	return ssc_depth;
+}
+
+int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock,
+		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
+{
+	int ret;
+	u8 n, clk_divider, mcu_cnt, div;
+
+	if (!card_clock) {
+		ucr->cur_clk = 0;
+		return 0;
+	}
+
+	if (initial_mode) {
+		/* We use 250k(around) here, in initial stage */
+		clk_divider = SD_CLK_DIVIDE_128;
+		card_clock = 30000000;
+	} else {
+		clk_divider = SD_CLK_DIVIDE_0;
+	}
+
+	ret = rtsx_usb_write_register(ucr, SD_CFG1,
+			SD_CLK_DIVIDE_MASK, clk_divider);
+	if (ret < 0)
+		return ret;
+
+	card_clock /= 1000000;
+	dev_dbg(&ucr->pusb_intf->dev,
+			"Switch card clock to %dMHz\n", card_clock);
+
+	if (!initial_mode && double_clk)
+		card_clock *= 2;
+	dev_dbg(&ucr->pusb_intf->dev,
+			"Internal SSC clock: %dMHz (cur_clk = %d)\n",
+			card_clock, ucr->cur_clk);
+
+	if (card_clock == ucr->cur_clk)
+		return 0;
+
+	/* Converting clock value into internal settings: n and div */
+	n = card_clock - 2;
+	if ((card_clock <= 2) || (n > MAX_DIV_N))
+		return -EINVAL;
+
+	mcu_cnt = 60/card_clock + 3;
+	if (mcu_cnt > 15)
+		mcu_cnt = 15;
+
+	/* Make sure that the SSC clock div_n is not less than MIN_DIV_N */
+
+	div = CLK_DIV_1;
+	while (n < MIN_DIV_N && div < CLK_DIV_4) {
+		n = (n + 2) * 2 - 2;
+		div++;
+	}
+	dev_dbg(&ucr->pusb_intf->dev, "n = %d, div = %d\n", n, div);
+
+	if (double_clk)
+		ssc_depth = double_ssc_depth(ssc_depth);
+
+	ssc_depth = revise_ssc_depth(ssc_depth, div);
+	dev_dbg(&ucr->pusb_intf->dev, "ssc_depth = %d\n", ssc_depth);
+
+	rtsx_usb_init_cmd(ucr);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV,
+			0x3F, (div << 4) | mcu_cnt);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL2,
+			SSC_DEPTH_MASK, ssc_depth);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
+	if (vpclk) {
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+				PHASE_NOT_RESET, 0);
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+				PHASE_NOT_RESET, PHASE_NOT_RESET);
+	}
+
+	ret = rtsx_usb_send_cmd(ucr, MODE_C, 2000);
+	if (ret < 0)
+		return ret;
+
+	ret = rtsx_usb_write_register(ucr, SSC_CTL1, 0xff,
+			SSC_RSTB | SSC_8X_EN | SSC_SEL_4M);
+	if (ret < 0)
+		return ret;
+
+	/* Wait SSC clock stable */
+	usleep_range(100, 1000);
+
+	ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0);
+	if (ret < 0)
+		return ret;
+
+	ucr->cur_clk = card_clock;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_switch_clock);
+
+int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card)
+{
+	int ret;
+	u16 val;
+	u16 cd_mask[] = {
+		[RTSX_USB_SD_CARD] = (CD_MASK & ~SD_CD),
+		[RTSX_USB_MS_CARD] = (CD_MASK & ~MS_CD)
+	};
+
+	ret = rtsx_usb_get_card_status(ucr, &val);
+	/*
+	 * If get status fails, return 0 (ok) for the exclusive check
+	 * and let the flow fail at somewhere else.
+	 */
+	if (ret)
+		return 0;
+
+	if (val & cd_mask[card])
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_card_exclusive_check);
+
+static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr)
+{
+	int ret;
+	u8 val;
+
+	rtsx_usb_init_cmd(ucr);
+
+	if (CHECK_PKG(ucr, LQFP48)) {
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
+				LDO3318_PWR_MASK, LDO_SUSPEND);
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
+				FORCE_LDO_POWERB, FORCE_LDO_POWERB);
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1,
+				0x30, 0x10);
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5,
+				0x03, 0x01);
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6,
+				0x0C, 0x04);
+	}
+
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SYS_DUMMY0, NYET_MSAK, NYET_EN);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CD_DEGLITCH_WIDTH, 0xFF, 0x08);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+			CD_DEGLITCH_EN, XD_CD_DEGLITCH_EN, 0x0);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+			SD30_DRIVE_MASK, DRIVER_TYPE_D);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+			CARD_DRIVE_SEL, SD20_DRIVE_MASK, 0x0);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, 0xE0, 0x0);
+
+	if (ucr->is_rts5179)
+		rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+				CARD_PULL_CTL5, 0x03, 0x01);
+
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DMA1_CTL,
+		       EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
+	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_INT_PEND,
+			XD_INT | MS_INT | SD_INT,
+			XD_INT | MS_INT | SD_INT);
+
+	ret = rtsx_usb_send_cmd(ucr, MODE_C, 100);
+	if (ret)
+		return ret;
+
+	/* config non-crystal mode */
+	rtsx_usb_read_register(ucr, CFG_MODE, &val);
+	if ((val & XTAL_FREE) || ((val & CLK_MODE_MASK) == CLK_MODE_NON_XTAL)) {
+		ret = rtsx_usb_write_phy_register(ucr, 0xC2, 0x7C);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int rtsx_usb_init_chip(struct rtsx_ucr *ucr)
+{
+	int ret;
+	u8 val;
+
+	rtsx_usb_clear_fsm_err(ucr);
+
+	/* power on SSC */
+	ret = rtsx_usb_write_register(ucr,
+			FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
+	if (ret)
+		return ret;
+
+	usleep_range(100, 1000);
+	ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0x00);
+	if (ret)
+		return ret;
+
+	/* determine IC version */
+	ret = rtsx_usb_read_register(ucr, HW_VERSION, &val);
+	if (ret)
+		return ret;
+
+	ucr->ic_version = val & HW_VER_MASK;
+
+	/* determine package */
+	ret = rtsx_usb_read_register(ucr, CARD_SHARE_MODE, &val);
+	if (ret)
+		return ret;
+
+	if (val & CARD_SHARE_LQFP_SEL) {
+		ucr->package = LQFP48;
+		dev_dbg(&ucr->pusb_intf->dev, "Package: LQFP48\n");
+	} else {
+		ucr->package = QFN24;
+		dev_dbg(&ucr->pusb_intf->dev, "Package: QFN24\n");
+	}
+
+	/* determine IC variations */
+	rtsx_usb_read_register(ucr, CFG_MODE_1, &val);
+	if (val & RTS5179) {
+		ucr->is_rts5179 = true;
+		dev_dbg(&ucr->pusb_intf->dev, "Device is rts5179\n");
+	} else {
+		ucr->is_rts5179 = false;
+	}
+
+	return rtsx_usb_reset_chip(ucr);
+}
+
+static int rtsx_usb_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	struct rtsx_ucr *ucr;
+	int ret;
+
+	dev_dbg(&intf->dev,
+		": Realtek USB Card Reader found at bus %03d address %03d\n",
+		 usb_dev->bus->busnum, usb_dev->devnum);
+
+	ucr = devm_kzalloc(&intf->dev, sizeof(*ucr), GFP_KERNEL);
+	if (!ucr)
+		return -ENOMEM;
+
+	ucr->pusb_dev = usb_dev;
+
+	ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
+			GFP_KERNEL, &ucr->iobuf_dma);
+	if (!ucr->iobuf)
+		return -ENOMEM;
+
+	usb_set_intfdata(intf, ucr);
+
+	ucr->vendor_id = id->idVendor;
+	ucr->product_id = id->idProduct;
+	ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
+
+	mutex_init(&ucr->dev_mutex);
+
+	ucr->pusb_intf = intf;
+
+	/* initialize */
+	ret = rtsx_usb_init_chip(ucr);
+	if (ret)
+		goto out_init_fail;
+
+	/* initialize USB SG transfer timer */
+	timer_setup(&ucr->sg_timer, rtsx_usb_sg_timed_out, 0);
+
+	ret = mfd_add_hotplug_devices(&intf->dev, rtsx_usb_cells,
+				      ARRAY_SIZE(rtsx_usb_cells));
+	if (ret)
+		goto out_init_fail;
+
+#ifdef CONFIG_PM
+	intf->needs_remote_wakeup = 1;
+	usb_enable_autosuspend(usb_dev);
+#endif
+
+	return 0;
+
+out_init_fail:
+	usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
+			ucr->iobuf_dma);
+	return ret;
+}
+
+static void rtsx_usb_disconnect(struct usb_interface *intf)
+{
+	struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+	dev_dbg(&intf->dev, "%s called\n", __func__);
+
+	mfd_remove_devices(&intf->dev);
+
+	usb_set_intfdata(ucr->pusb_intf, NULL);
+	usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
+			ucr->iobuf_dma);
+}
+
+#ifdef CONFIG_PM
+static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct rtsx_ucr *ucr =
+		(struct rtsx_ucr *)usb_get_intfdata(intf);
+	u16 val = 0;
+
+	dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n",
+			__func__, message.event);
+
+	if (PMSG_IS_AUTO(message)) {
+		if (mutex_trylock(&ucr->dev_mutex)) {
+			rtsx_usb_get_card_status(ucr, &val);
+			mutex_unlock(&ucr->dev_mutex);
+
+			/* Defer the autosuspend if card exists */
+			if (val & (SD_CD | MS_CD))
+				return -EAGAIN;
+		} else {
+			/* There is an ongoing operation*/
+			return -EAGAIN;
+		}
+	}
+
+	return 0;
+}
+
+static int rtsx_usb_resume(struct usb_interface *intf)
+{
+	return 0;
+}
+
+static int rtsx_usb_reset_resume(struct usb_interface *intf)
+{
+	struct rtsx_ucr *ucr =
+		(struct rtsx_ucr *)usb_get_intfdata(intf);
+
+	rtsx_usb_reset_chip(ucr);
+	return 0;
+}
+
+#else /* CONFIG_PM */
+
+#define rtsx_usb_suspend NULL
+#define rtsx_usb_resume NULL
+#define rtsx_usb_reset_resume NULL
+
+#endif /* CONFIG_PM */
+
+
+static int rtsx_usb_pre_reset(struct usb_interface *intf)
+{
+	struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+	mutex_lock(&ucr->dev_mutex);
+	return 0;
+}
+
+static int rtsx_usb_post_reset(struct usb_interface *intf)
+{
+	struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+	mutex_unlock(&ucr->dev_mutex);
+	return 0;
+}
+
+static struct usb_device_id rtsx_usb_usb_ids[] = {
+	{ USB_DEVICE(0x0BDA, 0x0129) },
+	{ USB_DEVICE(0x0BDA, 0x0139) },
+	{ USB_DEVICE(0x0BDA, 0x0140) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, rtsx_usb_usb_ids);
+
+static struct usb_driver rtsx_usb_driver = {
+	.name			= "rtsx_usb",
+	.probe			= rtsx_usb_probe,
+	.disconnect		= rtsx_usb_disconnect,
+	.suspend		= rtsx_usb_suspend,
+	.resume			= rtsx_usb_resume,
+	.reset_resume		= rtsx_usb_reset_resume,
+	.pre_reset		= rtsx_usb_pre_reset,
+	.post_reset		= rtsx_usb_post_reset,
+	.id_table		= rtsx_usb_usb_ids,
+	.supports_autosuspend	= 1,
+	.soft_unbind		= 1,
+};
+
+module_usb_driver(rtsx_usb_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
+MODULE_DESCRIPTION("Realtek USB Card Reader Driver");
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 567028c..cec8152 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -838,14 +838,14 @@  config MMC_USDHI6ROL0
 
 config MMC_REALTEK_PCI
 	tristate "Realtek PCI-E SD/MMC Card Interface Driver"
-	depends on MFD_RTSX_PCI
+	depends on MISC_RTSX_PCI
 	help
 	  Say Y here to include driver code to support SD/MMC card interface
 	  of Realtek PCI-E card reader
 
 config MMC_REALTEK_USB
 	tristate "Realtek USB SD/MMC Card Interface Driver"
-	depends on MFD_RTSX_USB
+	depends on MISC_RTSX_USB
 	help
 	  Say Y here to include driver code to support SD/MMC card interface
 	  of Realtek RTS5129/39 series card reader
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 0848dc0..30bd808 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -30,7 +30,7 @@ 
 #include <linux/mmc/sd.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/card.h>
-#include <linux/mfd/rtsx_pci.h>
+#include <linux/rtsx_pci.h>
 #include <asm/unaligned.h>
 
 struct realtek_pci_sdmmc {
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
index 76da168..7842207 100644
--- a/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -31,7 +31,7 @@ 
 #include <linux/scatterlist.h>
 #include <linux/pm_runtime.h>
 
-#include <linux/mfd/rtsx_usb.h>
+#include <linux/rtsx_usb.h>
 #include <asm/unaligned.h>
 
 #if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
diff --git a/include/linux/mfd/rtsx_common.h b/include/linux/mfd/rtsx_common.h
deleted file mode 100644
index 443176e..0000000
--- a/include/linux/mfd/rtsx_common.h
+++ /dev/null
@@ -1,50 +0,0 @@ 
-/* Driver for Realtek driver-based card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- */
-
-#ifndef __RTSX_COMMON_H
-#define __RTSX_COMMON_H
-
-#define DRV_NAME_RTSX_PCI		"rtsx_pci"
-#define DRV_NAME_RTSX_PCI_SDMMC		"rtsx_pci_sdmmc"
-#define DRV_NAME_RTSX_PCI_MS		"rtsx_pci_ms"
-
-#define RTSX_REG_PAIR(addr, val)	(((u32)(addr) << 16) | (u8)(val))
-
-#define RTSX_SSC_DEPTH_4M		0x01
-#define RTSX_SSC_DEPTH_2M		0x02
-#define RTSX_SSC_DEPTH_1M		0x03
-#define RTSX_SSC_DEPTH_500K		0x04
-#define RTSX_SSC_DEPTH_250K		0x05
-
-#define RTSX_SD_CARD			0
-#define RTSX_MS_CARD			1
-
-#define CLK_TO_DIV_N			0
-#define DIV_N_TO_CLK			1
-
-struct platform_device;
-
-struct rtsx_slot {
-	struct platform_device	*p_dev;
-	void			(*card_event)(struct platform_device *p_dev);
-};
-
-#endif
diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h
deleted file mode 100644
index c3d3f04..0000000
--- a/include/linux/mfd/rtsx_pci.h
+++ /dev/null
@@ -1,1141 +0,0 @@ 
-/* Driver for Realtek PCI-Express card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Wei WANG <wei_wang@realsil.com.cn>
- */
-
-#ifndef __RTSX_PCI_H
-#define __RTSX_PCI_H
-
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/mfd/rtsx_common.h>
-
-#define MAX_RW_REG_CNT			1024
-
-#define RTSX_HCBAR			0x00
-#define RTSX_HCBCTLR			0x04
-#define   STOP_CMD			(0x01 << 28)
-#define   READ_REG_CMD			0
-#define   WRITE_REG_CMD			1
-#define   CHECK_REG_CMD			2
-
-#define RTSX_HDBAR			0x08
-#define   SG_INT			0x04
-#define   SG_END			0x02
-#define   SG_VALID			0x01
-#define   SG_NO_OP			0x00
-#define   SG_TRANS_DATA			(0x02 << 4)
-#define   SG_LINK_DESC			(0x03 << 4)
-#define RTSX_HDBCTLR			0x0C
-#define   SDMA_MODE			0x00
-#define   ADMA_MODE			(0x02 << 26)
-#define   STOP_DMA			(0x01 << 28)
-#define   TRIG_DMA			(0x01 << 31)
-
-#define RTSX_HAIMR			0x10
-#define   HAIMR_TRANS_START		(0x01 << 31)
-#define   HAIMR_READ			0x00
-#define   HAIMR_WRITE			(0x01 << 30)
-#define   HAIMR_READ_START		(HAIMR_TRANS_START | HAIMR_READ)
-#define   HAIMR_WRITE_START		(HAIMR_TRANS_START | HAIMR_WRITE)
-#define   HAIMR_TRANS_END			(HAIMR_TRANS_START)
-
-#define RTSX_BIPR			0x14
-#define   CMD_DONE_INT			(1 << 31)
-#define   DATA_DONE_INT			(1 << 30)
-#define   TRANS_OK_INT			(1 << 29)
-#define   TRANS_FAIL_INT		(1 << 28)
-#define   XD_INT			(1 << 27)
-#define   MS_INT			(1 << 26)
-#define   SD_INT			(1 << 25)
-#define   GPIO0_INT			(1 << 24)
-#define   OC_INT			(1 << 23)
-#define   SD_WRITE_PROTECT		(1 << 19)
-#define   XD_EXIST			(1 << 18)
-#define   MS_EXIST			(1 << 17)
-#define   SD_EXIST			(1 << 16)
-#define   DELINK_INT			GPIO0_INT
-#define   MS_OC_INT			(1 << 23)
-#define   SD_OC_INT			(1 << 22)
-
-#define CARD_INT		(XD_INT | MS_INT | SD_INT)
-#define NEED_COMPLETE_INT	(DATA_DONE_INT | TRANS_OK_INT | TRANS_FAIL_INT)
-#define RTSX_INT		(CMD_DONE_INT | NEED_COMPLETE_INT | \
-					CARD_INT | GPIO0_INT | OC_INT)
-#define CARD_EXIST		(XD_EXIST | MS_EXIST | SD_EXIST)
-
-#define RTSX_BIER			0x18
-#define   CMD_DONE_INT_EN		(1 << 31)
-#define   DATA_DONE_INT_EN		(1 << 30)
-#define   TRANS_OK_INT_EN		(1 << 29)
-#define   TRANS_FAIL_INT_EN		(1 << 28)
-#define   XD_INT_EN			(1 << 27)
-#define   MS_INT_EN			(1 << 26)
-#define   SD_INT_EN			(1 << 25)
-#define   GPIO0_INT_EN			(1 << 24)
-#define   OC_INT_EN			(1 << 23)
-#define   DELINK_INT_EN			GPIO0_INT_EN
-#define   MS_OC_INT_EN			(1 << 23)
-#define   SD_OC_INT_EN			(1 << 22)
-
-
-/*
- * macros for easy use
- */
-#define rtsx_pci_writel(pcr, reg, value) \
-	iowrite32(value, (pcr)->remap_addr + reg)
-#define rtsx_pci_readl(pcr, reg) \
-	ioread32((pcr)->remap_addr + reg)
-#define rtsx_pci_writew(pcr, reg, value) \
-	iowrite16(value, (pcr)->remap_addr + reg)
-#define rtsx_pci_readw(pcr, reg) \
-	ioread16((pcr)->remap_addr + reg)
-#define rtsx_pci_writeb(pcr, reg, value) \
-	iowrite8(value, (pcr)->remap_addr + reg)
-#define rtsx_pci_readb(pcr, reg) \
-	ioread8((pcr)->remap_addr + reg)
-
-#define rtsx_pci_read_config_byte(pcr, where, val) \
-	pci_read_config_byte((pcr)->pci, where, val)
-
-#define rtsx_pci_write_config_byte(pcr, where, val) \
-	pci_write_config_byte((pcr)->pci, where, val)
-
-#define rtsx_pci_read_config_dword(pcr, where, val) \
-	pci_read_config_dword((pcr)->pci, where, val)
-
-#define rtsx_pci_write_config_dword(pcr, where, val) \
-	pci_write_config_dword((pcr)->pci, where, val)
-
-#define STATE_TRANS_NONE		0
-#define STATE_TRANS_CMD			1
-#define STATE_TRANS_BUF			2
-#define STATE_TRANS_SG			3
-
-#define TRANS_NOT_READY			0
-#define TRANS_RESULT_OK			1
-#define TRANS_RESULT_FAIL		2
-#define TRANS_NO_DEVICE			3
-
-#define RTSX_RESV_BUF_LEN		4096
-#define HOST_CMDS_BUF_LEN		1024
-#define HOST_SG_TBL_BUF_LEN		(RTSX_RESV_BUF_LEN - HOST_CMDS_BUF_LEN)
-#define HOST_SG_TBL_ITEMS		(HOST_SG_TBL_BUF_LEN / 8)
-#define MAX_SG_ITEM_LEN			0x80000
-#define HOST_TO_DEVICE			0
-#define DEVICE_TO_HOST			1
-
-#define OUTPUT_3V3			0
-#define OUTPUT_1V8			1
-
-#define RTSX_PHASE_MAX			32
-#define RX_TUNING_CNT			3
-
-#define MS_CFG				0xFD40
-#define   SAMPLE_TIME_RISING		0x00
-#define   SAMPLE_TIME_FALLING		0x80
-#define   PUSH_TIME_DEFAULT		0x00
-#define   PUSH_TIME_ODD			0x40
-#define   NO_EXTEND_TOGGLE		0x00
-#define   EXTEND_TOGGLE_CHK		0x20
-#define   MS_BUS_WIDTH_1		0x00
-#define   MS_BUS_WIDTH_4		0x10
-#define   MS_BUS_WIDTH_8		0x18
-#define   MS_2K_SECTOR_MODE		0x04
-#define   MS_512_SECTOR_MODE		0x00
-#define   MS_TOGGLE_TIMEOUT_EN		0x00
-#define   MS_TOGGLE_TIMEOUT_DISEN	0x01
-#define MS_NO_CHECK_INT			0x02
-#define MS_TPC				0xFD41
-#define MS_TRANS_CFG			0xFD42
-#define   WAIT_INT			0x80
-#define   NO_WAIT_INT			0x00
-#define   NO_AUTO_READ_INT_REG		0x00
-#define   AUTO_READ_INT_REG		0x40
-#define   MS_CRC16_ERR			0x20
-#define   MS_RDY_TIMEOUT		0x10
-#define   MS_INT_CMDNK			0x08
-#define   MS_INT_BREQ			0x04
-#define   MS_INT_ERR			0x02
-#define   MS_INT_CED			0x01
-#define MS_TRANSFER			0xFD43
-#define   MS_TRANSFER_START		0x80
-#define   MS_TRANSFER_END		0x40
-#define   MS_TRANSFER_ERR		0x20
-#define   MS_BS_STATE			0x10
-#define   MS_TM_READ_BYTES		0x00
-#define   MS_TM_NORMAL_READ		0x01
-#define   MS_TM_WRITE_BYTES		0x04
-#define   MS_TM_NORMAL_WRITE		0x05
-#define   MS_TM_AUTO_READ		0x08
-#define   MS_TM_AUTO_WRITE		0x0C
-#define MS_INT_REG			0xFD44
-#define MS_BYTE_CNT			0xFD45
-#define MS_SECTOR_CNT_L			0xFD46
-#define MS_SECTOR_CNT_H			0xFD47
-#define MS_DBUS_H			0xFD48
-
-#define SD_CFG1				0xFDA0
-#define   SD_CLK_DIVIDE_0		0x00
-#define   SD_CLK_DIVIDE_256		0xC0
-#define   SD_CLK_DIVIDE_128		0x80
-#define   SD_BUS_WIDTH_1BIT		0x00
-#define   SD_BUS_WIDTH_4BIT		0x01
-#define   SD_BUS_WIDTH_8BIT		0x02
-#define   SD_ASYNC_FIFO_NOT_RST		0x10
-#define   SD_20_MODE			0x00
-#define   SD_DDR_MODE			0x04
-#define   SD_30_MODE			0x08
-#define   SD_CLK_DIVIDE_MASK		0xC0
-#define SD_CFG2				0xFDA1
-#define   SD_CALCULATE_CRC7		0x00
-#define   SD_NO_CALCULATE_CRC7		0x80
-#define   SD_CHECK_CRC16		0x00
-#define   SD_NO_CHECK_CRC16		0x40
-#define   SD_NO_CHECK_WAIT_CRC_TO	0x20
-#define   SD_WAIT_BUSY_END		0x08
-#define   SD_NO_WAIT_BUSY_END		0x00
-#define   SD_CHECK_CRC7			0x00
-#define   SD_NO_CHECK_CRC7		0x04
-#define   SD_RSP_LEN_0			0x00
-#define   SD_RSP_LEN_6			0x01
-#define   SD_RSP_LEN_17			0x02
-#define   SD_RSP_TYPE_R0		0x04
-#define   SD_RSP_TYPE_R1		0x01
-#define   SD_RSP_TYPE_R1b		0x09
-#define   SD_RSP_TYPE_R2		0x02
-#define   SD_RSP_TYPE_R3		0x05
-#define   SD_RSP_TYPE_R4		0x05
-#define   SD_RSP_TYPE_R5		0x01
-#define   SD_RSP_TYPE_R6		0x01
-#define   SD_RSP_TYPE_R7		0x01
-#define SD_CFG3				0xFDA2
-#define   SD_RSP_80CLK_TIMEOUT_EN	0x01
-
-#define SD_STAT1			0xFDA3
-#define   SD_CRC7_ERR			0x80
-#define   SD_CRC16_ERR			0x40
-#define   SD_CRC_WRITE_ERR		0x20
-#define   SD_CRC_WRITE_ERR_MASK		0x1C
-#define   GET_CRC_TIME_OUT		0x02
-#define   SD_TUNING_COMPARE_ERR		0x01
-#define SD_STAT2			0xFDA4
-#define   SD_RSP_80CLK_TIMEOUT		0x01
-
-#define SD_BUS_STAT			0xFDA5
-#define   SD_CLK_TOGGLE_EN		0x80
-#define   SD_CLK_FORCE_STOP		0x40
-#define   SD_DAT3_STATUS		0x10
-#define   SD_DAT2_STATUS		0x08
-#define   SD_DAT1_STATUS		0x04
-#define   SD_DAT0_STATUS		0x02
-#define   SD_CMD_STATUS			0x01
-#define SD_PAD_CTL			0xFDA6
-#define   SD_IO_USING_1V8		0x80
-#define   SD_IO_USING_3V3		0x7F
-#define   TYPE_A_DRIVING		0x00
-#define   TYPE_B_DRIVING		0x01
-#define   TYPE_C_DRIVING		0x02
-#define   TYPE_D_DRIVING		0x03
-#define SD_SAMPLE_POINT_CTL		0xFDA7
-#define   DDR_FIX_RX_DAT		0x00
-#define   DDR_VAR_RX_DAT		0x80
-#define   DDR_FIX_RX_DAT_EDGE		0x00
-#define   DDR_FIX_RX_DAT_14_DELAY	0x40
-#define   DDR_FIX_RX_CMD		0x00
-#define   DDR_VAR_RX_CMD		0x20
-#define   DDR_FIX_RX_CMD_POS_EDGE	0x00
-#define   DDR_FIX_RX_CMD_14_DELAY	0x10
-#define   SD20_RX_POS_EDGE		0x00
-#define   SD20_RX_14_DELAY		0x08
-#define SD20_RX_SEL_MASK		0x08
-#define SD_PUSH_POINT_CTL		0xFDA8
-#define   DDR_FIX_TX_CMD_DAT		0x00
-#define   DDR_VAR_TX_CMD_DAT		0x80
-#define   DDR_FIX_TX_DAT_14_TSU		0x00
-#define   DDR_FIX_TX_DAT_12_TSU		0x40
-#define   DDR_FIX_TX_CMD_NEG_EDGE	0x00
-#define   DDR_FIX_TX_CMD_14_AHEAD	0x20
-#define   SD20_TX_NEG_EDGE		0x00
-#define   SD20_TX_14_AHEAD		0x10
-#define   SD20_TX_SEL_MASK		0x10
-#define   DDR_VAR_SDCLK_POL_SWAP	0x01
-#define SD_CMD0				0xFDA9
-#define   SD_CMD_START			0x40
-#define SD_CMD1				0xFDAA
-#define SD_CMD2				0xFDAB
-#define SD_CMD3				0xFDAC
-#define SD_CMD4				0xFDAD
-#define SD_CMD5				0xFDAE
-#define SD_BYTE_CNT_L			0xFDAF
-#define SD_BYTE_CNT_H			0xFDB0
-#define SD_BLOCK_CNT_L			0xFDB1
-#define SD_BLOCK_CNT_H			0xFDB2
-#define SD_TRANSFER			0xFDB3
-#define   SD_TRANSFER_START		0x80
-#define   SD_TRANSFER_END		0x40
-#define   SD_STAT_IDLE			0x20
-#define   SD_TRANSFER_ERR		0x10
-#define   SD_TM_NORMAL_WRITE		0x00
-#define   SD_TM_AUTO_WRITE_3		0x01
-#define   SD_TM_AUTO_WRITE_4		0x02
-#define   SD_TM_AUTO_READ_3		0x05
-#define   SD_TM_AUTO_READ_4		0x06
-#define   SD_TM_CMD_RSP			0x08
-#define   SD_TM_AUTO_WRITE_1		0x09
-#define   SD_TM_AUTO_WRITE_2		0x0A
-#define   SD_TM_NORMAL_READ		0x0C
-#define   SD_TM_AUTO_READ_1		0x0D
-#define   SD_TM_AUTO_READ_2		0x0E
-#define   SD_TM_AUTO_TUNING		0x0F
-#define SD_CMD_STATE			0xFDB5
-#define   SD_CMD_IDLE			0x80
-
-#define SD_DATA_STATE			0xFDB6
-#define   SD_DATA_IDLE			0x80
-
-#define SRCTL				0xFC13
-
-#define DCM_DRP_CTL			0xFC23
-#define   DCM_RESET			0x08
-#define   DCM_LOCKED			0x04
-#define   DCM_208M			0x00
-#define   DCM_TX			0x01
-#define   DCM_RX			0x02
-#define DCM_DRP_TRIG			0xFC24
-#define   DRP_START			0x80
-#define   DRP_DONE			0x40
-#define DCM_DRP_CFG			0xFC25
-#define   DRP_WRITE			0x80
-#define   DRP_READ			0x00
-#define   DCM_WRITE_ADDRESS_50		0x50
-#define   DCM_WRITE_ADDRESS_51		0x51
-#define   DCM_READ_ADDRESS_00		0x00
-#define   DCM_READ_ADDRESS_51		0x51
-#define DCM_DRP_WR_DATA_L		0xFC26
-#define DCM_DRP_WR_DATA_H		0xFC27
-#define DCM_DRP_RD_DATA_L		0xFC28
-#define DCM_DRP_RD_DATA_H		0xFC29
-#define SD_VPCLK0_CTL			0xFC2A
-#define SD_VPCLK1_CTL			0xFC2B
-#define   PHASE_SELECT_MASK		0x1F
-#define SD_DCMPS0_CTL			0xFC2C
-#define SD_DCMPS1_CTL			0xFC2D
-#define SD_VPTX_CTL			SD_VPCLK0_CTL
-#define SD_VPRX_CTL			SD_VPCLK1_CTL
-#define   PHASE_CHANGE			0x80
-#define   PHASE_NOT_RESET		0x40
-#define SD_DCMPS_TX_CTL			SD_DCMPS0_CTL
-#define SD_DCMPS_RX_CTL			SD_DCMPS1_CTL
-#define   DCMPS_CHANGE			0x80
-#define   DCMPS_CHANGE_DONE		0x40
-#define   DCMPS_ERROR			0x20
-#define   DCMPS_CURRENT_PHASE		0x1F
-#define CARD_CLK_SOURCE			0xFC2E
-#define   CRC_FIX_CLK			(0x00 << 0)
-#define   CRC_VAR_CLK0			(0x01 << 0)
-#define   CRC_VAR_CLK1			(0x02 << 0)
-#define   SD30_FIX_CLK			(0x00 << 2)
-#define   SD30_VAR_CLK0			(0x01 << 2)
-#define   SD30_VAR_CLK1			(0x02 << 2)
-#define   SAMPLE_FIX_CLK		(0x00 << 4)
-#define   SAMPLE_VAR_CLK0		(0x01 << 4)
-#define   SAMPLE_VAR_CLK1		(0x02 << 4)
-#define CARD_PWR_CTL			0xFD50
-#define   PMOS_STRG_MASK		0x10
-#define   PMOS_STRG_800mA		0x10
-#define   PMOS_STRG_400mA		0x00
-#define   SD_POWER_OFF			0x03
-#define   SD_PARTIAL_POWER_ON		0x01
-#define   SD_POWER_ON			0x00
-#define   SD_POWER_MASK			0x03
-#define   MS_POWER_OFF			0x0C
-#define   MS_PARTIAL_POWER_ON		0x04
-#define   MS_POWER_ON			0x00
-#define   MS_POWER_MASK			0x0C
-#define   BPP_POWER_OFF			0x0F
-#define   BPP_POWER_5_PERCENT_ON	0x0E
-#define   BPP_POWER_10_PERCENT_ON	0x0C
-#define   BPP_POWER_15_PERCENT_ON	0x08
-#define   BPP_POWER_ON			0x00
-#define   BPP_POWER_MASK		0x0F
-#define   SD_VCC_PARTIAL_POWER_ON	0x02
-#define   SD_VCC_POWER_ON		0x00
-#define CARD_CLK_SWITCH			0xFD51
-#define RTL8411B_PACKAGE_MODE		0xFD51
-#define CARD_SHARE_MODE			0xFD52
-#define   CARD_SHARE_MASK		0x0F
-#define   CARD_SHARE_MULTI_LUN		0x00
-#define   CARD_SHARE_NORMAL		0x00
-#define   CARD_SHARE_48_SD		0x04
-#define   CARD_SHARE_48_MS		0x08
-#define   CARD_SHARE_BAROSSA_SD		0x01
-#define   CARD_SHARE_BAROSSA_MS		0x02
-#define CARD_DRIVE_SEL			0xFD53
-#define   MS_DRIVE_8mA			(0x01 << 6)
-#define   MMC_DRIVE_8mA			(0x01 << 4)
-#define   XD_DRIVE_8mA			(0x01 << 2)
-#define   GPIO_DRIVE_8mA		0x01
-#define RTS5209_CARD_DRIVE_DEFAULT	(MS_DRIVE_8mA | MMC_DRIVE_8mA |\
-					XD_DRIVE_8mA | GPIO_DRIVE_8mA)
-#define RTL8411_CARD_DRIVE_DEFAULT	(MS_DRIVE_8mA | MMC_DRIVE_8mA |\
-					XD_DRIVE_8mA)
-#define RTSX_CARD_DRIVE_DEFAULT		(MS_DRIVE_8mA | GPIO_DRIVE_8mA)
-
-#define CARD_STOP			0xFD54
-#define   SPI_STOP			0x01
-#define   XD_STOP			0x02
-#define   SD_STOP			0x04
-#define   MS_STOP			0x08
-#define   SPI_CLR_ERR			0x10
-#define   XD_CLR_ERR			0x20
-#define   SD_CLR_ERR			0x40
-#define   MS_CLR_ERR			0x80
-#define CARD_OE				0xFD55
-#define   SD_OUTPUT_EN			0x04
-#define   MS_OUTPUT_EN			0x08
-#define CARD_AUTO_BLINK			0xFD56
-#define CARD_GPIO_DIR			0xFD57
-#define CARD_GPIO			0xFD58
-#define CARD_DATA_SOURCE		0xFD5B
-#define   PINGPONG_BUFFER		0x01
-#define   RING_BUFFER			0x00
-#define SD30_CLK_DRIVE_SEL		0xFD5A
-#define   DRIVER_TYPE_A			0x05
-#define   DRIVER_TYPE_B			0x03
-#define   DRIVER_TYPE_C			0x02
-#define   DRIVER_TYPE_D			0x01
-#define CARD_SELECT			0xFD5C
-#define   SD_MOD_SEL			2
-#define   MS_MOD_SEL			3
-#define SD30_DRIVE_SEL			0xFD5E
-#define   CFG_DRIVER_TYPE_A		0x02
-#define   CFG_DRIVER_TYPE_B		0x03
-#define   CFG_DRIVER_TYPE_C		0x01
-#define   CFG_DRIVER_TYPE_D		0x00
-#define SD30_CMD_DRIVE_SEL		0xFD5E
-#define SD30_DAT_DRIVE_SEL		0xFD5F
-#define CARD_CLK_EN			0xFD69
-#define   SD_CLK_EN			0x04
-#define   MS_CLK_EN			0x08
-#define SDIO_CTRL			0xFD6B
-#define CD_PAD_CTL			0xFD73
-#define   CD_DISABLE_MASK		0x07
-#define   MS_CD_DISABLE			0x04
-#define   SD_CD_DISABLE			0x02
-#define   XD_CD_DISABLE			0x01
-#define   CD_DISABLE			0x07
-#define   CD_ENABLE			0x00
-#define   MS_CD_EN_ONLY			0x03
-#define   SD_CD_EN_ONLY			0x05
-#define   XD_CD_EN_ONLY			0x06
-#define   FORCE_CD_LOW_MASK		0x38
-#define   FORCE_CD_XD_LOW		0x08
-#define   FORCE_CD_SD_LOW		0x10
-#define   FORCE_CD_MS_LOW		0x20
-#define   CD_AUTO_DISABLE		0x40
-#define FPDCTL				0xFC00
-#define   SSC_POWER_DOWN		0x01
-#define   SD_OC_POWER_DOWN		0x02
-#define   ALL_POWER_DOWN		0x07
-#define   OC_POWER_DOWN			0x06
-#define PDINFO				0xFC01
-
-#define CLK_CTL				0xFC02
-#define   CHANGE_CLK			0x01
-#define   CLK_LOW_FREQ			0x01
-
-#define CLK_DIV				0xFC03
-#define   CLK_DIV_1			0x01
-#define   CLK_DIV_2			0x02
-#define   CLK_DIV_4			0x03
-#define   CLK_DIV_8			0x04
-#define CLK_SEL				0xFC04
-
-#define SSC_DIV_N_0			0xFC0F
-#define SSC_DIV_N_1			0xFC10
-#define SSC_CTL1			0xFC11
-#define    SSC_RSTB			0x80
-#define    SSC_8X_EN			0x40
-#define    SSC_FIX_FRAC			0x20
-#define    SSC_SEL_1M			0x00
-#define    SSC_SEL_2M			0x08
-#define    SSC_SEL_4M			0x10
-#define    SSC_SEL_8M			0x18
-#define SSC_CTL2			0xFC12
-#define    SSC_DEPTH_MASK		0x07
-#define    SSC_DEPTH_DISALBE		0x00
-#define    SSC_DEPTH_4M			0x01
-#define    SSC_DEPTH_2M			0x02
-#define    SSC_DEPTH_1M			0x03
-#define    SSC_DEPTH_500K		0x04
-#define    SSC_DEPTH_250K		0x05
-#define RCCTL				0xFC14
-
-#define FPGA_PULL_CTL			0xFC1D
-#define OLT_LED_CTL			0xFC1E
-#define GPIO_CTL			0xFC1F
-
-#define LDO_CTL				0xFC1E
-#define   BPP_ASIC_1V7			0x00
-#define   BPP_ASIC_1V8			0x01
-#define   BPP_ASIC_1V9			0x02
-#define   BPP_ASIC_2V0			0x03
-#define   BPP_ASIC_2V7			0x04
-#define   BPP_ASIC_2V8			0x05
-#define   BPP_ASIC_3V2			0x06
-#define   BPP_ASIC_3V3			0x07
-#define   BPP_REG_TUNED18		0x07
-#define   BPP_TUNED18_SHIFT_8402	5
-#define   BPP_TUNED18_SHIFT_8411	4
-#define   BPP_PAD_MASK			0x04
-#define   BPP_PAD_3V3			0x04
-#define   BPP_PAD_1V8			0x00
-#define   BPP_LDO_POWB			0x03
-#define   BPP_LDO_ON			0x00
-#define   BPP_LDO_SUSPEND		0x02
-#define   BPP_LDO_OFF			0x03
-#define SYS_VER				0xFC32
-
-#define CARD_PULL_CTL1			0xFD60
-#define CARD_PULL_CTL2			0xFD61
-#define CARD_PULL_CTL3			0xFD62
-#define CARD_PULL_CTL4			0xFD63
-#define CARD_PULL_CTL5			0xFD64
-#define CARD_PULL_CTL6			0xFD65
-
-/* PCI Express Related Registers */
-#define IRQEN0				0xFE20
-#define IRQSTAT0			0xFE21
-#define    DMA_DONE_INT			0x80
-#define    SUSPEND_INT			0x40
-#define    LINK_RDY_INT			0x20
-#define    LINK_DOWN_INT		0x10
-#define IRQEN1				0xFE22
-#define IRQSTAT1			0xFE23
-#define TLPRIEN				0xFE24
-#define TLPRISTAT			0xFE25
-#define TLPTIEN				0xFE26
-#define TLPTISTAT			0xFE27
-#define DMATC0				0xFE28
-#define DMATC1				0xFE29
-#define DMATC2				0xFE2A
-#define DMATC3				0xFE2B
-#define DMACTL				0xFE2C
-#define   DMA_RST			0x80
-#define   DMA_BUSY			0x04
-#define   DMA_DIR_TO_CARD		0x00
-#define   DMA_DIR_FROM_CARD		0x02
-#define   DMA_EN			0x01
-#define   DMA_128			(0 << 4)
-#define   DMA_256			(1 << 4)
-#define   DMA_512			(2 << 4)
-#define   DMA_1024			(3 << 4)
-#define   DMA_PACK_SIZE_MASK		0x30
-#define BCTL				0xFE2D
-#define RBBC0				0xFE2E
-#define RBBC1				0xFE2F
-#define RBDAT				0xFE30
-#define RBCTL				0xFE34
-#define CFGADDR0			0xFE35
-#define CFGADDR1			0xFE36
-#define CFGDATA0			0xFE37
-#define CFGDATA1			0xFE38
-#define CFGDATA2			0xFE39
-#define CFGDATA3			0xFE3A
-#define CFGRWCTL			0xFE3B
-#define PHYRWCTL			0xFE3C
-#define PHYDATA0			0xFE3D
-#define PHYDATA1			0xFE3E
-#define PHYADDR				0xFE3F
-#define MSGRXDATA0			0xFE40
-#define MSGRXDATA1			0xFE41
-#define MSGRXDATA2			0xFE42
-#define MSGRXDATA3			0xFE43
-#define MSGTXDATA0			0xFE44
-#define MSGTXDATA1			0xFE45
-#define MSGTXDATA2			0xFE46
-#define MSGTXDATA3			0xFE47
-#define MSGTXCTL			0xFE48
-#define LTR_CTL				0xFE4A
-#define LTR_TX_EN_MASK		BIT(7)
-#define LTR_TX_EN_1			BIT(7)
-#define LTR_TX_EN_0			0
-#define LTR_LATENCY_MODE_MASK		BIT(6)
-#define LTR_LATENCY_MODE_HW		0
-#define LTR_LATENCY_MODE_SW		BIT(6)
-#define OBFF_CFG			0xFE4C
-
-#define CDRESUMECTL			0xFE52
-#define WAKE_SEL_CTL			0xFE54
-#define PCLK_CTL			0xFE55
-#define   PCLK_MODE_SEL			0x20
-#define PME_FORCE_CTL			0xFE56
-
-#define ASPM_FORCE_CTL			0xFE57
-#define   FORCE_ASPM_CTL0		0x10
-#define   FORCE_ASPM_VAL_MASK		0x03
-#define   FORCE_ASPM_L1_EN		0x02
-#define   FORCE_ASPM_L0_EN		0x01
-#define   FORCE_ASPM_NO_ASPM		0x00
-#define PM_CLK_FORCE_CTL		0xFE58
-#define FUNC_FORCE_CTL			0xFE59
-#define   FUNC_FORCE_UPME_XMT_DBG	0x02
-#define PERST_GLITCH_WIDTH		0xFE5C
-#define CHANGE_LINK_STATE		0xFE5B
-#define RESET_LOAD_REG			0xFE5E
-#define EFUSE_CONTENT			0xFE5F
-#define HOST_SLEEP_STATE		0xFE60
-#define   HOST_ENTER_S1			1
-#define   HOST_ENTER_S3			2
-
-#define SDIO_CFG			0xFE70
-#define PM_EVENT_DEBUG			0xFE71
-#define   PME_DEBUG_0			0x08
-#define NFTS_TX_CTRL			0xFE72
-
-#define PWR_GATE_CTRL			0xFE75
-#define   PWR_GATE_EN			0x01
-#define   LDO3318_PWR_MASK		0x06
-#define   LDO_ON			0x00
-#define   LDO_SUSPEND			0x04
-#define   LDO_OFF			0x06
-#define PWD_SUSPEND_EN			0xFE76
-#define LDO_PWR_SEL			0xFE78
-
-#define L1SUB_CONFIG1			0xFE8D
-#define L1SUB_CONFIG2			0xFE8E
-#define   L1SUB_AUTO_CFG		0x02
-#define L1SUB_CONFIG3			0xFE8F
-#define   L1OFF_MBIAS2_EN_5250		BIT(7)
-
-#define DUMMY_REG_RESET_0		0xFE90
-
-#define AUTOLOAD_CFG_BASE		0xFF00
-#define PETXCFG				0xFF03
-#define FORCE_CLKREQ_DELINK_MASK	BIT(7)
-#define FORCE_CLKREQ_LOW	0x80
-#define FORCE_CLKREQ_HIGH	0x00
-
-#define PM_CTRL1			0xFF44
-#define   CD_RESUME_EN_MASK		0xF0
-
-#define PM_CTRL2			0xFF45
-#define PM_CTRL3			0xFF46
-#define   SDIO_SEND_PME_EN		0x80
-#define   FORCE_RC_MODE_ON		0x40
-#define   FORCE_RX50_LINK_ON		0x20
-#define   D3_DELINK_MODE_EN		0x10
-#define   USE_PESRTB_CTL_DELINK		0x08
-#define   DELAY_PIN_WAKE		0x04
-#define   RESET_PIN_WAKE		0x02
-#define   PM_WAKE_EN			0x01
-#define PM_CTRL4			0xFF47
-
-/* Memory mapping */
-#define SRAM_BASE			0xE600
-#define RBUF_BASE			0xF400
-#define PPBUF_BASE1			0xF800
-#define PPBUF_BASE2			0xFA00
-#define IMAGE_FLAG_ADDR0		0xCE80
-#define IMAGE_FLAG_ADDR1		0xCE81
-
-#define RREF_CFG			0xFF6C
-#define   RREF_VBGSEL_MASK		0x38
-#define   RREF_VBGSEL_1V25		0x28
-
-#define OOBS_CONFIG			0xFF6E
-#define   OOBS_AUTOK_DIS		0x80
-#define   OOBS_VAL_MASK			0x1F
-
-#define LDO_DV18_CFG			0xFF70
-#define   LDO_DV18_SR_MASK		0xC0
-#define   LDO_DV18_SR_DF		0x40
-
-#define LDO_CONFIG2			0xFF71
-#define   LDO_D3318_MASK		0x07
-#define   LDO_D3318_33V			0x07
-#define   LDO_D3318_18V			0x02
-
-#define LDO_VCC_CFG0			0xFF72
-#define   LDO_VCC_LMTVTH_MASK		0x30
-#define   LDO_VCC_LMTVTH_2A		0x10
-
-#define LDO_VCC_CFG1			0xFF73
-#define   LDO_VCC_REF_TUNE_MASK		0x30
-#define   LDO_VCC_REF_1V2		0x20
-#define   LDO_VCC_TUNE_MASK		0x07
-#define   LDO_VCC_1V8			0x04
-#define   LDO_VCC_3V3			0x07
-#define   LDO_VCC_LMT_EN		0x08
-
-#define LDO_VIO_CFG			0xFF75
-#define   LDO_VIO_SR_MASK		0xC0
-#define   LDO_VIO_SR_DF			0x40
-#define   LDO_VIO_REF_TUNE_MASK		0x30
-#define   LDO_VIO_REF_1V2		0x20
-#define   LDO_VIO_TUNE_MASK		0x07
-#define   LDO_VIO_1V7			0x03
-#define   LDO_VIO_1V8			0x04
-#define   LDO_VIO_3V3			0x07
-
-#define LDO_DV12S_CFG			0xFF76
-#define   LDO_REF12_TUNE_MASK		0x18
-#define   LDO_REF12_TUNE_DF		0x10
-#define   LDO_D12_TUNE_MASK		0x07
-#define   LDO_D12_TUNE_DF		0x04
-
-#define LDO_AV12S_CFG			0xFF77
-#define   LDO_AV12S_TUNE_MASK		0x07
-#define   LDO_AV12S_TUNE_DF		0x04
-
-#define SD40_LDO_CTL1			0xFE7D
-#define   SD40_VIO_TUNE_MASK		0x70
-#define   SD40_VIO_TUNE_1V7		0x30
-#define   SD_VIO_LDO_1V8		0x40
-#define   SD_VIO_LDO_3V3		0x70
-
-/* Phy register */
-#define PHY_PCR				0x00
-#define   PHY_PCR_FORCE_CODE		0xB000
-#define   PHY_PCR_OOBS_CALI_50		0x0800
-#define   PHY_PCR_OOBS_VCM_08		0x0200
-#define   PHY_PCR_OOBS_SEN_90		0x0040
-#define   PHY_PCR_RSSI_EN		0x0002
-#define   PHY_PCR_RX10K			0x0001
-
-#define PHY_RCR0			0x01
-#define PHY_RCR1			0x02
-#define   PHY_RCR1_ADP_TIME_4		0x0400
-#define   PHY_RCR1_VCO_COARSE		0x001F
-#define   PHY_RCR1_INIT_27S		0x0A1F
-#define PHY_SSCCR2			0x02
-#define   PHY_SSCCR2_PLL_NCODE		0x0A00
-#define   PHY_SSCCR2_TIME0		0x001C
-#define   PHY_SSCCR2_TIME2_WIDTH	0x0003
-
-#define PHY_RCR2			0x03
-#define   PHY_RCR2_EMPHASE_EN		0x8000
-#define   PHY_RCR2_NADJR		0x4000
-#define   PHY_RCR2_CDR_SR_2		0x0100
-#define   PHY_RCR2_FREQSEL_12		0x0040
-#define   PHY_RCR2_CDR_SC_12P		0x0010
-#define   PHY_RCR2_CALIB_LATE		0x0002
-#define   PHY_RCR2_INIT_27S		0xC152
-#define PHY_SSCCR3			0x03
-#define   PHY_SSCCR3_STEP_IN		0x2740
-#define   PHY_SSCCR3_CHECK_DELAY	0x0008
-#define _PHY_ANA03			0x03
-#define   _PHY_ANA03_TIMER_MAX		0x2700
-#define   _PHY_ANA03_OOBS_DEB_EN	0x0040
-#define   _PHY_CMU_DEBUG_EN		0x0008
-
-#define PHY_RTCR			0x04
-#define PHY_RDR				0x05
-#define   PHY_RDR_RXDSEL_1_9		0x4000
-#define   PHY_SSC_AUTO_PWD		0x0600
-#define PHY_TCR0			0x06
-#define PHY_TCR1			0x07
-#define PHY_TUNE			0x08
-#define   PHY_TUNE_TUNEREF_1_0		0x4000
-#define   PHY_TUNE_VBGSEL_1252		0x0C00
-#define   PHY_TUNE_SDBUS_33		0x0200
-#define   PHY_TUNE_TUNED18		0x01C0
-#define   PHY_TUNE_TUNED12		0X0020
-#define   PHY_TUNE_TUNEA12		0x0004
-#define   PHY_TUNE_VOLTAGE_MASK		0xFC3F
-#define   PHY_TUNE_VOLTAGE_3V3		0x03C0
-#define   PHY_TUNE_D18_1V8		0x0100
-#define   PHY_TUNE_D18_1V7		0x0080
-#define PHY_ANA08			0x08
-#define   PHY_ANA08_RX_EQ_DCGAIN	0x5000
-#define   PHY_ANA08_SEL_RX_EN		0x0400
-#define   PHY_ANA08_RX_EQ_VAL		0x03C0
-#define   PHY_ANA08_SCP			0x0020
-#define   PHY_ANA08_SEL_IPI		0x0004
-
-#define PHY_IMR				0x09
-#define PHY_BPCR			0x0A
-#define   PHY_BPCR_IBRXSEL		0x0400
-#define   PHY_BPCR_IBTXSEL		0x0100
-#define   PHY_BPCR_IB_FILTER		0x0080
-#define   PHY_BPCR_CMIRROR_EN		0x0040
-
-#define PHY_BIST			0x0B
-#define PHY_RAW_L			0x0C
-#define PHY_RAW_H			0x0D
-#define PHY_RAW_DATA			0x0E
-#define PHY_HOST_CLK_CTRL		0x0F
-#define PHY_DMR				0x10
-#define PHY_BACR			0x11
-#define   PHY_BACR_BASIC_MASK		0xFFF3
-#define PHY_IER				0x12
-#define PHY_BCSR			0x13
-#define PHY_BPR				0x14
-#define PHY_BPNR2			0x15
-#define PHY_BPNR			0x16
-#define PHY_BRNR2			0x17
-#define PHY_BENR			0x18
-#define PHY_REV				0x19
-#define   PHY_REV_RESV			0xE000
-#define   PHY_REV_RXIDLE_LATCHED	0x1000
-#define   PHY_REV_P1_EN			0x0800
-#define   PHY_REV_RXIDLE_EN		0x0400
-#define   PHY_REV_CLKREQ_TX_EN		0x0200
-#define   PHY_REV_CLKREQ_RX_EN		0x0100
-#define   PHY_REV_CLKREQ_DT_1_0		0x0040
-#define   PHY_REV_STOP_CLKRD		0x0020
-#define   PHY_REV_RX_PWST		0x0008
-#define   PHY_REV_STOP_CLKWR		0x0004
-#define _PHY_REV0			0x19
-#define   _PHY_REV0_FILTER_OUT		0x3800
-#define   _PHY_REV0_CDR_BYPASS_PFD	0x0100
-#define   _PHY_REV0_CDR_RX_IDLE_BYPASS	0x0002
-
-#define PHY_FLD0			0x1A
-#define PHY_ANA1A			0x1A
-#define   PHY_ANA1A_TXR_LOOPBACK	0x2000
-#define   PHY_ANA1A_RXT_BIST		0x0500
-#define   PHY_ANA1A_TXR_BIST		0x0040
-#define   PHY_ANA1A_REV			0x0006
-#define   PHY_FLD0_INIT_27S		0x2546
-#define PHY_FLD1			0x1B
-#define PHY_FLD2			0x1C
-#define PHY_FLD3			0x1D
-#define   PHY_FLD3_TIMER_4		0x0800
-#define   PHY_FLD3_TIMER_6		0x0020
-#define   PHY_FLD3_RXDELINK		0x0004
-#define   PHY_FLD3_INIT_27S		0x0004
-#define PHY_ANA1D			0x1D
-#define   PHY_ANA1D_DEBUG_ADDR		0x0004
-#define _PHY_FLD0			0x1D
-#define   _PHY_FLD0_CLK_REQ_20C		0x8000
-#define   _PHY_FLD0_RX_IDLE_EN		0x1000
-#define   _PHY_FLD0_BIT_ERR_RSTN	0x0800
-#define   _PHY_FLD0_BER_COUNT		0x01E0
-#define   _PHY_FLD0_BER_TIMER		0x001E
-#define   _PHY_FLD0_CHECK_EN		0x0001
-
-#define PHY_FLD4			0x1E
-#define   PHY_FLD4_FLDEN_SEL		0x4000
-#define   PHY_FLD4_REQ_REF		0x2000
-#define   PHY_FLD4_RXAMP_OFF		0x1000
-#define   PHY_FLD4_REQ_ADDA		0x0800
-#define   PHY_FLD4_BER_COUNT		0x00E0
-#define   PHY_FLD4_BER_TIMER		0x000A
-#define   PHY_FLD4_BER_CHK_EN		0x0001
-#define   PHY_FLD4_INIT_27S		0x5C7F
-#define PHY_DIG1E			0x1E
-#define   PHY_DIG1E_REV			0x4000
-#define   PHY_DIG1E_D0_X_D1		0x1000
-#define   PHY_DIG1E_RX_ON_HOST		0x0800
-#define   PHY_DIG1E_RCLK_REF_HOST	0x0400
-#define   PHY_DIG1E_RCLK_TX_EN_KEEP	0x0040
-#define   PHY_DIG1E_RCLK_TX_TERM_KEEP	0x0020
-#define   PHY_DIG1E_RCLK_RX_EIDLE_ON	0x0010
-#define   PHY_DIG1E_TX_TERM_KEEP	0x0008
-#define   PHY_DIG1E_RX_TERM_KEEP	0x0004
-#define   PHY_DIG1E_TX_EN_KEEP		0x0002
-#define   PHY_DIG1E_RX_EN_KEEP		0x0001
-#define PHY_DUM_REG			0x1F
-
-#define PCR_ASPM_SETTING_REG1		0x160
-#define PCR_ASPM_SETTING_REG2		0x168
-
-#define PCR_SETTING_REG1		0x724
-#define PCR_SETTING_REG2		0x814
-#define PCR_SETTING_REG3		0x747
-
-#define rtsx_pci_init_cmd(pcr)		((pcr)->ci = 0)
-
-#define RTS5227_DEVICE_ID		0x5227
-#define RTS_MAX_TIMES_FREQ_REDUCTION	8
-
-struct rtsx_pcr;
-
-struct pcr_handle {
-	struct rtsx_pcr			*pcr;
-};
-
-struct pcr_ops {
-	int (*write_phy)(struct rtsx_pcr *pcr, u8 addr, u16 val);
-	int (*read_phy)(struct rtsx_pcr *pcr, u8 addr, u16 *val);
-	int		(*extra_init_hw)(struct rtsx_pcr *pcr);
-	int		(*optimize_phy)(struct rtsx_pcr *pcr);
-	int		(*turn_on_led)(struct rtsx_pcr *pcr);
-	int		(*turn_off_led)(struct rtsx_pcr *pcr);
-	int		(*enable_auto_blink)(struct rtsx_pcr *pcr);
-	int		(*disable_auto_blink)(struct rtsx_pcr *pcr);
-	int		(*card_power_on)(struct rtsx_pcr *pcr, int card);
-	int		(*card_power_off)(struct rtsx_pcr *pcr, int card);
-	int		(*switch_output_voltage)(struct rtsx_pcr *pcr,
-						u8 voltage);
-	unsigned int	(*cd_deglitch)(struct rtsx_pcr *pcr);
-	int		(*conv_clk_and_div_n)(int clk, int dir);
-	void		(*fetch_vendor_settings)(struct rtsx_pcr *pcr);
-	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
-
-	void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
-	int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency);
-	int (*set_l1off_sub)(struct rtsx_pcr *pcr, u8 val);
-	void (*set_l1off_cfg_sub_d0)(struct rtsx_pcr *pcr, int active);
-	void (*full_on)(struct rtsx_pcr *pcr);
-	void (*power_saving)(struct rtsx_pcr *pcr);
-};
-
-enum PDEV_STAT  {PDEV_STAT_IDLE, PDEV_STAT_RUN};
-
-#define ASPM_L1_1_EN_MASK		BIT(3)
-#define ASPM_L1_2_EN_MASK		BIT(2)
-#define PM_L1_1_EN_MASK		BIT(1)
-#define PM_L1_2_EN_MASK		BIT(0)
-
-#define ASPM_L1_1_EN			BIT(0)
-#define ASPM_L1_2_EN			BIT(1)
-#define PM_L1_1_EN				BIT(2)
-#define PM_L1_2_EN				BIT(3)
-#define LTR_L1SS_PWR_GATE_EN	BIT(4)
-#define L1_SNOOZE_TEST_EN		BIT(5)
-#define LTR_L1SS_PWR_GATE_CHECK_CARD_EN	BIT(6)
-
-enum dev_aspm_mode {
-	DEV_ASPM_DYNAMIC,
-	DEV_ASPM_BACKDOOR,
-	DEV_ASPM_STATIC,
-	DEV_ASPM_DISABLE,
-};
-
-/*
- * struct rtsx_cr_option  - card reader option
- * @dev_flags: device flags
- * @force_clkreq_0: force clock request
- * @ltr_en: enable ltr mode flag
- * @ltr_enabled: ltr mode in configure space flag
- * @ltr_active: ltr mode status
- * @ltr_active_latency: ltr mode active latency
- * @ltr_idle_latency: ltr mode idle latency
- * @ltr_l1off_latency: ltr mode l1off latency
- * @dev_aspm_mode: device aspm mode
- * @l1_snooze_delay: l1 snooze delay
- * @ltr_l1off_sspwrgate: ltr l1off sspwrgate
- * @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate
- */
-struct rtsx_cr_option {
-	u32 dev_flags;
-	bool force_clkreq_0;
-	bool ltr_en;
-	bool ltr_enabled;
-	bool ltr_active;
-	u32 ltr_active_latency;
-	u32 ltr_idle_latency;
-	u32 ltr_l1off_latency;
-	enum dev_aspm_mode dev_aspm_mode;
-	u32 l1_snooze_delay;
-	u8 ltr_l1off_sspwrgate;
-	u8 ltr_l1off_snooze_sspwrgate;
-};
-
-#define rtsx_set_dev_flag(cr, flag) \
-	((cr)->option.dev_flags |= (flag))
-#define rtsx_clear_dev_flag(cr, flag) \
-	((cr)->option.dev_flags &= ~(flag))
-#define rtsx_check_dev_flag(cr, flag) \
-	((cr)->option.dev_flags & (flag))
-
-struct rtsx_pcr {
-	struct pci_dev			*pci;
-	unsigned int			id;
-	int				pcie_cap;
-	struct rtsx_cr_option	option;
-
-	/* pci resources */
-	unsigned long			addr;
-	void __iomem			*remap_addr;
-	int				irq;
-
-	/* host reserved buffer */
-	void				*rtsx_resv_buf;
-	dma_addr_t			rtsx_resv_buf_addr;
-
-	void				*host_cmds_ptr;
-	dma_addr_t			host_cmds_addr;
-	int				ci;
-
-	void				*host_sg_tbl_ptr;
-	dma_addr_t			host_sg_tbl_addr;
-	int				sgi;
-
-	u32				bier;
-	char				trans_result;
-
-	unsigned int			card_inserted;
-	unsigned int			card_removed;
-	unsigned int			card_exist;
-
-	struct delayed_work		carddet_work;
-	struct delayed_work		idle_work;
-
-	spinlock_t			lock;
-	struct mutex			pcr_mutex;
-	struct completion		*done;
-	struct completion		*finish_me;
-
-	unsigned int			cur_clock;
-	bool				remove_pci;
-	bool				msi_en;
-
-#define EXTRA_CAPS_SD_SDR50		(1 << 0)
-#define EXTRA_CAPS_SD_SDR104		(1 << 1)
-#define EXTRA_CAPS_SD_DDR50		(1 << 2)
-#define EXTRA_CAPS_MMC_HSDDR		(1 << 3)
-#define EXTRA_CAPS_MMC_HS200		(1 << 4)
-#define EXTRA_CAPS_MMC_8BIT		(1 << 5)
-	u32				extra_caps;
-
-#define IC_VER_A			0
-#define IC_VER_B			1
-#define IC_VER_C			2
-#define IC_VER_D			3
-	u8				ic_version;
-
-	u8				sd30_drive_sel_1v8;
-	u8				sd30_drive_sel_3v3;
-	u8				card_drive_sel;
-#define ASPM_L1_EN			0x02
-	u8				aspm_en;
-	bool				aspm_enabled;
-
-#define PCR_MS_PMOS			(1 << 0)
-#define PCR_REVERSE_SOCKET		(1 << 1)
-	u32				flags;
-
-	u32				tx_initial_phase;
-	u32				rx_initial_phase;
-
-	const u32			*sd_pull_ctl_enable_tbl;
-	const u32			*sd_pull_ctl_disable_tbl;
-	const u32			*ms_pull_ctl_enable_tbl;
-	const u32			*ms_pull_ctl_disable_tbl;
-
-	const struct pcr_ops		*ops;
-	enum PDEV_STAT			state;
-
-	u16				reg_pm_ctrl3;
-
-	int				num_slots;
-	struct rtsx_slot		*slots;
-
-	u8				dma_error_count;
-};
-
-#define PID_524A	0x524A
-#define PID_5249		0x5249
-#define PID_5250		0x5250
-#define PID_525A	0x525A
-
-#define CHK_PCI_PID(pcr, pid)		((pcr)->pci->device == (pid))
-#define PCI_VID(pcr)			((pcr)->pci->vendor)
-#define PCI_PID(pcr)			((pcr)->pci->device)
-#define is_version(pcr, pid, ver)				\
-	(CHK_PCI_PID(pcr, pid) && (pcr)->ic_version == (ver))
-#define pcr_dbg(pcr, fmt, arg...)				\
-	dev_dbg(&(pcr)->pci->dev, fmt, ##arg)
-
-#define SDR104_PHASE(val)		((val) & 0xFF)
-#define SDR50_PHASE(val)		(((val) >> 8) & 0xFF)
-#define DDR50_PHASE(val)		(((val) >> 16) & 0xFF)
-#define SDR104_TX_PHASE(pcr)		SDR104_PHASE((pcr)->tx_initial_phase)
-#define SDR50_TX_PHASE(pcr)		SDR50_PHASE((pcr)->tx_initial_phase)
-#define DDR50_TX_PHASE(pcr)		DDR50_PHASE((pcr)->tx_initial_phase)
-#define SDR104_RX_PHASE(pcr)		SDR104_PHASE((pcr)->rx_initial_phase)
-#define SDR50_RX_PHASE(pcr)		SDR50_PHASE((pcr)->rx_initial_phase)
-#define DDR50_RX_PHASE(pcr)		DDR50_PHASE((pcr)->rx_initial_phase)
-#define SET_CLOCK_PHASE(sdr104, sdr50, ddr50)	\
-				(((ddr50) << 16) | ((sdr50) << 8) | (sdr104))
-
-void rtsx_pci_start_run(struct rtsx_pcr *pcr);
-int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data);
-int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data);
-int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
-int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
-void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr);
-void rtsx_pci_add_cmd(struct rtsx_pcr *pcr,
-		u8 cmd_type, u16 reg_addr, u8 mask, u8 data);
-void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
-int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
-int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int num_sg, bool read, int timeout);
-int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int num_sg, bool read);
-void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int num_sg, bool read);
-int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
-		int count, bool read, int timeout);
-int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
-int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
-int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
-int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card);
-int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
-		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
-int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card);
-int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card);
-int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card);
-int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage);
-unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr);
-void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr);
-
-static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr)
-{
-	return (u8 *)(pcr->host_cmds_ptr);
-}
-
-static inline int rtsx_pci_update_cfg_byte(struct rtsx_pcr *pcr, int addr,
-		u8 mask, u8 append)
-{
-	int err;
-	u8 val;
-
-	err = pci_read_config_byte(pcr->pci, addr, &val);
-	if (err < 0)
-		return err;
-	return pci_write_config_byte(pcr->pci, addr, (val & mask) | append);
-}
-
-static inline void rtsx_pci_write_be32(struct rtsx_pcr *pcr, u16 reg, u32 val)
-{
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg,     0xFF, val >> 24);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, val >> 16);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, val >> 8);
-	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, val);
-}
-
-static inline int rtsx_pci_update_phy(struct rtsx_pcr *pcr, u8 addr,
-	u16 mask, u16 append)
-{
-	int err;
-	u16 val;
-
-	err = rtsx_pci_read_phy_register(pcr, addr, &val);
-	if (err < 0)
-		return err;
-
-	return rtsx_pci_write_phy_register(pcr, addr, (val & mask) | append);
-}
-
-#endif
diff --git a/include/linux/mfd/rtsx_usb.h b/include/linux/mfd/rtsx_usb.h
deleted file mode 100644
index c446e4f..0000000
--- a/include/linux/mfd/rtsx_usb.h
+++ /dev/null
@@ -1,628 +0,0 @@ 
-/* Driver for Realtek RTS5139 USB card reader
- *
- * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- *   Roger Tseng <rogerable@realtek.com>
- */
-
-#ifndef __RTSX_USB_H
-#define __RTSX_USB_H
-
-#include <linux/usb.h>
-
-/* related module names */
-#define RTSX_USB_SD_CARD	0
-#define RTSX_USB_MS_CARD	1
-
-/* endpoint numbers */
-#define EP_BULK_OUT		1
-#define EP_BULK_IN		2
-#define EP_INTR_IN		3
-
-/* USB vendor requests */
-#define RTSX_USB_REQ_REG_OP	0x00
-#define RTSX_USB_REQ_POLL	0x02
-
-/* miscellaneous parameters */
-#define MIN_DIV_N		60
-#define MAX_DIV_N		120
-
-#define MAX_PHASE		15
-#define RX_TUNING_CNT		3
-
-#define QFN24			0
-#define LQFP48			1
-#define CHECK_PKG(ucr, pkg)	((ucr)->package == (pkg))
-
-/* data structures */
-struct rtsx_ucr {
-	u16			vendor_id;
-	u16			product_id;
-
-	int			package;
-	u8			ic_version;
-	bool			is_rts5179;
-
-	unsigned int		cur_clk;
-
-	u8			*cmd_buf;
-	unsigned int		cmd_idx;
-	u8			*rsp_buf;
-
-	struct usb_device	*pusb_dev;
-	struct usb_interface	*pusb_intf;
-	struct usb_sg_request	current_sg;
-	unsigned char		*iobuf;
-	dma_addr_t		iobuf_dma;
-
-	struct timer_list	sg_timer;
-	struct mutex		dev_mutex;
-};
-
-/* buffer size */
-#define IOBUF_SIZE		1024
-
-/* prototypes of exported functions */
-extern int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status);
-
-extern int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data);
-extern int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask,
-		u8 data);
-
-extern int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask,
-		u8 data);
-extern int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr,
-		u8 *data);
-
-extern void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type,
-		u16 reg_addr, u8 mask, u8 data);
-extern int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout);
-extern int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout);
-extern int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
-			      void *buf, unsigned int len, int use_sg,
-			      unsigned int *act_len, int timeout);
-
-extern int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len);
-extern int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len);
-extern int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock,
-		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
-extern int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card);
-
-/* card status */
-#define SD_CD		0x01
-#define MS_CD		0x02
-#define XD_CD		0x04
-#define CD_MASK		(SD_CD | MS_CD | XD_CD)
-#define SD_WP		0x08
-
-/* reader command field offset & parameters */
-#define READ_REG_CMD		0
-#define WRITE_REG_CMD		1
-#define CHECK_REG_CMD		2
-
-#define PACKET_TYPE		4
-#define CNT_H			5
-#define CNT_L			6
-#define STAGE_FLAG		7
-#define CMD_OFFSET		8
-#define SEQ_WRITE_DATA_OFFSET	12
-
-#define BATCH_CMD		0
-#define SEQ_READ		1
-#define SEQ_WRITE		2
-
-#define STAGE_R			0x01
-#define STAGE_DI		0x02
-#define STAGE_DO		0x04
-#define STAGE_MS_STATUS		0x08
-#define STAGE_XD_STATUS		0x10
-#define MODE_C			0x00
-#define MODE_CR			(STAGE_R)
-#define MODE_CDIR		(STAGE_R | STAGE_DI)
-#define MODE_CDOR		(STAGE_R | STAGE_DO)
-
-#define EP0_OP_SHIFT		14
-#define EP0_READ_REG_CMD	2
-#define EP0_WRITE_REG_CMD	3
-
-#define rtsx_usb_cmd_hdr_tag(ucr)		\
-	do {					\
-		ucr->cmd_buf[0] = 'R';		\
-		ucr->cmd_buf[1] = 'T';		\
-		ucr->cmd_buf[2] = 'C';		\
-		ucr->cmd_buf[3] = 'R';		\
-	} while (0)
-
-static inline void rtsx_usb_init_cmd(struct rtsx_ucr *ucr)
-{
-	rtsx_usb_cmd_hdr_tag(ucr);
-	ucr->cmd_idx = 0;
-	ucr->cmd_buf[PACKET_TYPE] = BATCH_CMD;
-}
-
-/* internal register address */
-#define FPDCTL				0xFC00
-#define SSC_DIV_N_0			0xFC07
-#define SSC_CTL1			0xFC09
-#define SSC_CTL2			0xFC0A
-#define CFG_MODE			0xFC0E
-#define CFG_MODE_1			0xFC0F
-#define RCCTL				0xFC14
-#define SOF_WDOG			0xFC28
-#define SYS_DUMMY0			0xFC30
-
-#define MS_BLKEND			0xFD30
-#define MS_READ_START			0xFD31
-#define MS_READ_COUNT			0xFD32
-#define MS_WRITE_START			0xFD33
-#define MS_WRITE_COUNT			0xFD34
-#define MS_COMMAND			0xFD35
-#define MS_OLD_BLOCK_0			0xFD36
-#define MS_OLD_BLOCK_1			0xFD37
-#define MS_NEW_BLOCK_0			0xFD38
-#define MS_NEW_BLOCK_1			0xFD39
-#define MS_LOG_BLOCK_0			0xFD3A
-#define MS_LOG_BLOCK_1			0xFD3B
-#define MS_BUS_WIDTH			0xFD3C
-#define MS_PAGE_START			0xFD3D
-#define MS_PAGE_LENGTH			0xFD3E
-#define MS_CFG				0xFD40
-#define MS_TPC				0xFD41
-#define MS_TRANS_CFG			0xFD42
-#define MS_TRANSFER			0xFD43
-#define MS_INT_REG			0xFD44
-#define MS_BYTE_CNT			0xFD45
-#define MS_SECTOR_CNT_L			0xFD46
-#define MS_SECTOR_CNT_H			0xFD47
-#define MS_DBUS_H			0xFD48
-
-#define CARD_DMA1_CTL			0xFD5C
-#define CARD_PULL_CTL1			0xFD60
-#define CARD_PULL_CTL2			0xFD61
-#define CARD_PULL_CTL3			0xFD62
-#define CARD_PULL_CTL4			0xFD63
-#define CARD_PULL_CTL5			0xFD64
-#define CARD_PULL_CTL6			0xFD65
-#define CARD_EXIST			0xFD6F
-#define CARD_INT_PEND			0xFD71
-
-#define LDO_POWER_CFG			0xFD7B
-
-#define SD_CFG1				0xFDA0
-#define SD_CFG2				0xFDA1
-#define SD_CFG3				0xFDA2
-#define SD_STAT1			0xFDA3
-#define SD_STAT2			0xFDA4
-#define SD_BUS_STAT			0xFDA5
-#define SD_PAD_CTL			0xFDA6
-#define SD_SAMPLE_POINT_CTL		0xFDA7
-#define SD_PUSH_POINT_CTL		0xFDA8
-#define SD_CMD0				0xFDA9
-#define SD_CMD1				0xFDAA
-#define SD_CMD2				0xFDAB
-#define SD_CMD3				0xFDAC
-#define SD_CMD4				0xFDAD
-#define SD_CMD5				0xFDAE
-#define SD_BYTE_CNT_L			0xFDAF
-#define SD_BYTE_CNT_H			0xFDB0
-#define SD_BLOCK_CNT_L			0xFDB1
-#define SD_BLOCK_CNT_H			0xFDB2
-#define SD_TRANSFER			0xFDB3
-#define SD_CMD_STATE			0xFDB5
-#define SD_DATA_STATE			0xFDB6
-#define SD_VPCLK0_CTL			0xFC2A
-#define SD_VPCLK1_CTL			0xFC2B
-#define SD_DCMPS0_CTL			0xFC2C
-#define SD_DCMPS1_CTL			0xFC2D
-
-#define CARD_DMA1_CTL			0xFD5C
-
-#define HW_VERSION			0xFC01
-
-#define SSC_CLK_FPGA_SEL		0xFC02
-#define CLK_DIV				0xFC03
-#define SFSM_ED				0xFC04
-
-#define CD_DEGLITCH_WIDTH		0xFC20
-#define CD_DEGLITCH_EN			0xFC21
-#define AUTO_DELINK_EN			0xFC23
-
-#define FPGA_PULL_CTL			0xFC1D
-#define CARD_CLK_SOURCE			0xFC2E
-
-#define CARD_SHARE_MODE			0xFD51
-#define CARD_DRIVE_SEL			0xFD52
-#define CARD_STOP			0xFD53
-#define CARD_OE				0xFD54
-#define CARD_AUTO_BLINK			0xFD55
-#define CARD_GPIO			0xFD56
-#define SD30_DRIVE_SEL			0xFD57
-
-#define CARD_DATA_SOURCE		0xFD5D
-#define CARD_SELECT			0xFD5E
-
-#define CARD_CLK_EN			0xFD79
-#define CARD_PWR_CTL			0xFD7A
-
-#define OCPCTL				0xFD80
-#define OCPPARA1			0xFD81
-#define OCPPARA2			0xFD82
-#define OCPSTAT				0xFD83
-
-#define HS_USB_STAT			0xFE01
-#define HS_VCONTROL			0xFE26
-#define HS_VSTAIN			0xFE27
-#define HS_VLOADM			0xFE28
-#define HS_VSTAOUT			0xFE29
-
-#define MC_IRQ				0xFF00
-#define MC_IRQEN			0xFF01
-#define MC_FIFO_CTL			0xFF02
-#define MC_FIFO_BC0			0xFF03
-#define MC_FIFO_BC1			0xFF04
-#define MC_FIFO_STAT			0xFF05
-#define MC_FIFO_MODE			0xFF06
-#define MC_FIFO_RD_PTR0			0xFF07
-#define MC_FIFO_RD_PTR1			0xFF08
-#define MC_DMA_CTL			0xFF10
-#define MC_DMA_TC0			0xFF11
-#define MC_DMA_TC1			0xFF12
-#define MC_DMA_TC2			0xFF13
-#define MC_DMA_TC3			0xFF14
-#define MC_DMA_RST			0xFF15
-
-#define RBUF_SIZE_MASK			0xFBFF
-#define RBUF_BASE			0xF000
-#define PPBUF_BASE1			0xF800
-#define PPBUF_BASE2			0xFA00
-
-/* internal register value macros */
-#define POWER_OFF			0x03
-#define PARTIAL_POWER_ON		0x02
-#define POWER_ON			0x00
-#define POWER_MASK			0x03
-#define LDO3318_PWR_MASK		0x0C
-#define LDO_ON				0x00
-#define LDO_SUSPEND			0x08
-#define LDO_OFF				0x0C
-#define DV3318_AUTO_PWR_OFF		0x10
-#define FORCE_LDO_POWERB		0x60
-
-/* LDO_POWER_CFG */
-#define TUNE_SD18_MASK			0x1C
-#define TUNE_SD18_1V7			0x00
-#define TUNE_SD18_1V8			(0x01 << 2)
-#define TUNE_SD18_1V9			(0x02 << 2)
-#define TUNE_SD18_2V0			(0x03 << 2)
-#define TUNE_SD18_2V7			(0x04 << 2)
-#define TUNE_SD18_2V8			(0x05 << 2)
-#define TUNE_SD18_2V9			(0x06 << 2)
-#define TUNE_SD18_3V3			(0x07 << 2)
-
-/* CLK_DIV */
-#define CLK_CHANGE			0x80
-#define CLK_DIV_1			0x00
-#define CLK_DIV_2			0x01
-#define CLK_DIV_4			0x02
-#define CLK_DIV_8			0x03
-
-#define SSC_POWER_MASK			0x01
-#define SSC_POWER_DOWN			0x01
-#define SSC_POWER_ON			0x00
-
-#define FPGA_VER			0x80
-#define HW_VER_MASK			0x0F
-
-#define EXTEND_DMA1_ASYNC_SIGNAL	0x02
-
-/* CFG_MODE*/
-#define XTAL_FREE			0x80
-#define CLK_MODE_MASK			0x03
-#define CLK_MODE_12M_XTAL		0x00
-#define CLK_MODE_NON_XTAL		0x01
-#define CLK_MODE_24M_OSC		0x02
-#define CLK_MODE_48M_OSC		0x03
-
-/* CFG_MODE_1*/
-#define RTS5179				0x02
-
-#define NYET_EN				0x01
-#define NYET_MSAK			0x01
-
-#define SD30_DRIVE_MASK			0x07
-#define SD20_DRIVE_MASK			0x03
-
-#define DISABLE_SD_CD			0x08
-#define DISABLE_MS_CD			0x10
-#define DISABLE_XD_CD			0x20
-#define SD_CD_DEGLITCH_EN		0x01
-#define MS_CD_DEGLITCH_EN		0x02
-#define XD_CD_DEGLITCH_EN		0x04
-
-#define	CARD_SHARE_LQFP48		0x04
-#define	CARD_SHARE_QFN24		0x00
-#define CARD_SHARE_LQFP_SEL		0x04
-#define	CARD_SHARE_XD			0x00
-#define	CARD_SHARE_SD			0x01
-#define	CARD_SHARE_MS			0x02
-#define CARD_SHARE_MASK			0x03
-
-
-/* SD30_DRIVE_SEL */
-#define DRIVER_TYPE_A			0x05
-#define DRIVER_TYPE_B			0x03
-#define DRIVER_TYPE_C			0x02
-#define DRIVER_TYPE_D			0x01
-
-/* SD_BUS_STAT */
-#define	SD_CLK_TOGGLE_EN		0x80
-#define	SD_CLK_FORCE_STOP	        0x40
-#define	SD_DAT3_STATUS		        0x10
-#define	SD_DAT2_STATUS		        0x08
-#define	SD_DAT1_STATUS		        0x04
-#define	SD_DAT0_STATUS		        0x02
-#define	SD_CMD_STATUS			0x01
-
-/* SD_PAD_CTL */
-#define	SD_IO_USING_1V8		        0x80
-#define	SD_IO_USING_3V3		        0x7F
-#define	TYPE_A_DRIVING		        0x00
-#define	TYPE_B_DRIVING			0x01
-#define	TYPE_C_DRIVING			0x02
-#define	TYPE_D_DRIVING		        0x03
-
-/* CARD_CLK_EN */
-#define SD_CLK_EN			0x04
-#define MS_CLK_EN			0x08
-
-/* CARD_SELECT */
-#define SD_MOD_SEL			2
-#define MS_MOD_SEL			3
-
-/* CARD_SHARE_MODE */
-#define	CARD_SHARE_LQFP48		0x04
-#define	CARD_SHARE_QFN24		0x00
-#define CARD_SHARE_LQFP_SEL		0x04
-#define	CARD_SHARE_XD			0x00
-#define	CARD_SHARE_SD			0x01
-#define	CARD_SHARE_MS			0x02
-#define CARD_SHARE_MASK			0x03
-
-/* SSC_CTL1 */
-#define SSC_RSTB			0x80
-#define SSC_8X_EN			0x40
-#define SSC_FIX_FRAC			0x20
-#define SSC_SEL_1M			0x00
-#define SSC_SEL_2M			0x08
-#define SSC_SEL_4M			0x10
-#define SSC_SEL_8M			0x18
-
-/* SSC_CTL2 */
-#define SSC_DEPTH_MASK			0x03
-#define SSC_DEPTH_DISALBE		0x00
-#define SSC_DEPTH_2M			0x01
-#define SSC_DEPTH_1M			0x02
-#define SSC_DEPTH_512K			0x03
-
-/* SD_VPCLK0_CTL */
-#define PHASE_CHANGE			0x80
-#define PHASE_NOT_RESET			0x40
-
-/* SD_TRANSFER */
-#define	SD_TRANSFER_START		0x80
-#define	SD_TRANSFER_END			0x40
-#define SD_STAT_IDLE			0x20
-#define	SD_TRANSFER_ERR			0x10
-#define	SD_TM_NORMAL_WRITE		0x00
-#define	SD_TM_AUTO_WRITE_3		0x01
-#define	SD_TM_AUTO_WRITE_4		0x02
-#define	SD_TM_AUTO_READ_3		0x05
-#define	SD_TM_AUTO_READ_4		0x06
-#define	SD_TM_CMD_RSP			0x08
-#define	SD_TM_AUTO_WRITE_1		0x09
-#define	SD_TM_AUTO_WRITE_2		0x0A
-#define	SD_TM_NORMAL_READ		0x0C
-#define	SD_TM_AUTO_READ_1		0x0D
-#define	SD_TM_AUTO_READ_2		0x0E
-#define	SD_TM_AUTO_TUNING		0x0F
-
-/* SD_CFG1 */
-#define SD_CLK_DIVIDE_0			0x00
-#define	SD_CLK_DIVIDE_256		0xC0
-#define	SD_CLK_DIVIDE_128		0x80
-#define SD_CLK_DIVIDE_MASK		0xC0
-#define	SD_BUS_WIDTH_1BIT		0x00
-#define	SD_BUS_WIDTH_4BIT		0x01
-#define	SD_BUS_WIDTH_8BIT		0x02
-#define	SD_ASYNC_FIFO_RST		0x10
-#define	SD_20_MODE			0x00
-#define	SD_DDR_MODE			0x04
-#define	SD_30_MODE			0x08
-
-/* SD_CFG2 */
-#define	SD_CALCULATE_CRC7		0x00
-#define	SD_NO_CALCULATE_CRC7		0x80
-#define	SD_CHECK_CRC16			0x00
-#define	SD_NO_CHECK_CRC16		0x40
-#define SD_WAIT_CRC_TO_EN		0x20
-#define	SD_WAIT_BUSY_END		0x08
-#define	SD_NO_WAIT_BUSY_END		0x00
-#define	SD_CHECK_CRC7			0x00
-#define	SD_NO_CHECK_CRC7		0x04
-#define	SD_RSP_LEN_0			0x00
-#define	SD_RSP_LEN_6			0x01
-#define	SD_RSP_LEN_17			0x02
-#define	SD_RSP_TYPE_R0			0x04
-#define	SD_RSP_TYPE_R1			0x01
-#define	SD_RSP_TYPE_R1b			0x09
-#define	SD_RSP_TYPE_R2			0x02
-#define	SD_RSP_TYPE_R3			0x05
-#define	SD_RSP_TYPE_R4			0x05
-#define	SD_RSP_TYPE_R5			0x01
-#define	SD_RSP_TYPE_R6			0x01
-#define	SD_RSP_TYPE_R7			0x01
-
-/* SD_STAT1 */
-#define	SD_CRC7_ERR			0x80
-#define	SD_CRC16_ERR			0x40
-#define	SD_CRC_WRITE_ERR		0x20
-#define	SD_CRC_WRITE_ERR_MASK		0x1C
-#define	GET_CRC_TIME_OUT		0x02
-#define	SD_TUNING_COMPARE_ERR		0x01
-
-/* SD_DATA_STATE */
-#define SD_DATA_IDLE			0x80
-
-/* CARD_DATA_SOURCE */
-#define PINGPONG_BUFFER			0x01
-#define RING_BUFFER			0x00
-
-/* CARD_OE */
-#define SD_OUTPUT_EN			0x04
-#define MS_OUTPUT_EN			0x08
-
-/* CARD_STOP */
-#define SD_STOP				0x04
-#define MS_STOP				0x08
-#define SD_CLR_ERR			0x40
-#define MS_CLR_ERR			0x80
-
-/* CARD_CLK_SOURCE */
-#define CRC_FIX_CLK			(0x00 << 0)
-#define CRC_VAR_CLK0			(0x01 << 0)
-#define CRC_VAR_CLK1			(0x02 << 0)
-#define SD30_FIX_CLK			(0x00 << 2)
-#define SD30_VAR_CLK0			(0x01 << 2)
-#define SD30_VAR_CLK1			(0x02 << 2)
-#define SAMPLE_FIX_CLK			(0x00 << 4)
-#define SAMPLE_VAR_CLK0			(0x01 << 4)
-#define SAMPLE_VAR_CLK1			(0x02 << 4)
-
-/* SD_SAMPLE_POINT_CTL */
-#define	DDR_FIX_RX_DAT			0x00
-#define	DDR_VAR_RX_DAT			0x80
-#define	DDR_FIX_RX_DAT_EDGE		0x00
-#define	DDR_FIX_RX_DAT_14_DELAY		0x40
-#define	DDR_FIX_RX_CMD			0x00
-#define	DDR_VAR_RX_CMD			0x20
-#define	DDR_FIX_RX_CMD_POS_EDGE		0x00
-#define	DDR_FIX_RX_CMD_14_DELAY		0x10
-#define	SD20_RX_POS_EDGE		0x00
-#define	SD20_RX_14_DELAY		0x08
-#define SD20_RX_SEL_MASK		0x08
-
-/* SD_PUSH_POINT_CTL */
-#define	DDR_FIX_TX_CMD_DAT		0x00
-#define	DDR_VAR_TX_CMD_DAT		0x80
-#define	DDR_FIX_TX_DAT_14_TSU		0x00
-#define	DDR_FIX_TX_DAT_12_TSU		0x40
-#define	DDR_FIX_TX_CMD_NEG_EDGE		0x00
-#define	DDR_FIX_TX_CMD_14_AHEAD		0x20
-#define	SD20_TX_NEG_EDGE		0x00
-#define	SD20_TX_14_AHEAD		0x10
-#define SD20_TX_SEL_MASK		0x10
-#define	DDR_VAR_SDCLK_POL_SWAP		0x01
-
-/* MS_CFG */
-#define	SAMPLE_TIME_RISING		0x00
-#define	SAMPLE_TIME_FALLING		0x80
-#define	PUSH_TIME_DEFAULT		0x00
-#define	PUSH_TIME_ODD			0x40
-#define	NO_EXTEND_TOGGLE		0x00
-#define	EXTEND_TOGGLE_CHK		0x20
-#define	MS_BUS_WIDTH_1			0x00
-#define	MS_BUS_WIDTH_4			0x10
-#define	MS_BUS_WIDTH_8			0x18
-#define	MS_2K_SECTOR_MODE		0x04
-#define	MS_512_SECTOR_MODE		0x00
-#define	MS_TOGGLE_TIMEOUT_EN		0x00
-#define	MS_TOGGLE_TIMEOUT_DISEN		0x01
-#define MS_NO_CHECK_INT			0x02
-
-/* MS_TRANS_CFG */
-#define	WAIT_INT			0x80
-#define	NO_WAIT_INT			0x00
-#define	NO_AUTO_READ_INT_REG		0x00
-#define	AUTO_READ_INT_REG		0x40
-#define	MS_CRC16_ERR			0x20
-#define	MS_RDY_TIMEOUT			0x10
-#define	MS_INT_CMDNK			0x08
-#define	MS_INT_BREQ			0x04
-#define	MS_INT_ERR			0x02
-#define	MS_INT_CED			0x01
-
-/* MS_TRANSFER */
-#define	MS_TRANSFER_START		0x80
-#define	MS_TRANSFER_END			0x40
-#define	MS_TRANSFER_ERR			0x20
-#define	MS_BS_STATE			0x10
-#define	MS_TM_READ_BYTES		0x00
-#define	MS_TM_NORMAL_READ		0x01
-#define	MS_TM_WRITE_BYTES		0x04
-#define	MS_TM_NORMAL_WRITE		0x05
-#define	MS_TM_AUTO_READ			0x08
-#define	MS_TM_AUTO_WRITE		0x0C
-#define MS_TM_SET_CMD			0x06
-#define MS_TM_COPY_PAGE			0x07
-#define MS_TM_MULTI_READ		0x02
-#define MS_TM_MULTI_WRITE		0x03
-
-/* MC_FIFO_CTL */
-#define FIFO_FLUSH			0x01
-
-/* MC_DMA_RST */
-#define DMA_RESET  0x01
-
-/* MC_DMA_CTL */
-#define DMA_TC_EQ_0			0x80
-#define DMA_DIR_TO_CARD			0x00
-#define DMA_DIR_FROM_CARD		0x02
-#define DMA_EN				0x01
-#define DMA_128				(0 << 2)
-#define DMA_256				(1 << 2)
-#define DMA_512				(2 << 2)
-#define DMA_1024			(3 << 2)
-#define DMA_PACK_SIZE_MASK		0x0C
-
-/* CARD_INT_PEND */
-#define XD_INT				0x10
-#define MS_INT				0x08
-#define SD_INT				0x04
-
-/* LED operations*/
-static inline int rtsx_usb_turn_on_led(struct rtsx_ucr *ucr)
-{
-	return  rtsx_usb_ep0_write_register(ucr, CARD_GPIO, 0x03, 0x02);
-}
-
-static inline int rtsx_usb_turn_off_led(struct rtsx_ucr *ucr)
-{
-	return rtsx_usb_ep0_write_register(ucr, CARD_GPIO, 0x03, 0x03);
-}
-
-/* HW error clearing */
-static inline void rtsx_usb_clear_fsm_err(struct rtsx_ucr *ucr)
-{
-	rtsx_usb_ep0_write_register(ucr, SFSM_ED, 0xf8, 0xf8);
-}
-
-static inline void rtsx_usb_clear_dma_err(struct rtsx_ucr *ucr)
-{
-	rtsx_usb_ep0_write_register(ucr, MC_FIFO_CTL,
-			FIFO_FLUSH, FIFO_FLUSH);
-	rtsx_usb_ep0_write_register(ucr, MC_DMA_RST, DMA_RESET, DMA_RESET);
-}
-#endif /* __RTS51139_H */
diff --git a/include/linux/rtsx_common.h b/include/linux/rtsx_common.h
new file mode 100644
index 0000000..443176e
--- /dev/null
+++ b/include/linux/rtsx_common.h
@@ -0,0 +1,50 @@ 
+/* Driver for Realtek driver-based card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ */
+
+#ifndef __RTSX_COMMON_H
+#define __RTSX_COMMON_H
+
+#define DRV_NAME_RTSX_PCI		"rtsx_pci"
+#define DRV_NAME_RTSX_PCI_SDMMC		"rtsx_pci_sdmmc"
+#define DRV_NAME_RTSX_PCI_MS		"rtsx_pci_ms"
+
+#define RTSX_REG_PAIR(addr, val)	(((u32)(addr) << 16) | (u8)(val))
+
+#define RTSX_SSC_DEPTH_4M		0x01
+#define RTSX_SSC_DEPTH_2M		0x02
+#define RTSX_SSC_DEPTH_1M		0x03
+#define RTSX_SSC_DEPTH_500K		0x04
+#define RTSX_SSC_DEPTH_250K		0x05
+
+#define RTSX_SD_CARD			0
+#define RTSX_MS_CARD			1
+
+#define CLK_TO_DIV_N			0
+#define DIV_N_TO_CLK			1
+
+struct platform_device;
+
+struct rtsx_slot {
+	struct platform_device	*p_dev;
+	void			(*card_event)(struct platform_device *p_dev);
+};
+
+#endif
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
new file mode 100644
index 0000000..6781b5b
--- /dev/null
+++ b/include/linux/rtsx_pci.h
@@ -0,0 +1,1141 @@ 
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Wei WANG <wei_wang@realsil.com.cn>
+ */
+
+#ifndef __RTSX_PCI_H
+#define __RTSX_PCI_H
+
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/rtsx_common.h>
+
+#define MAX_RW_REG_CNT			1024
+
+#define RTSX_HCBAR			0x00
+#define RTSX_HCBCTLR			0x04
+#define   STOP_CMD			(0x01 << 28)
+#define   READ_REG_CMD			0
+#define   WRITE_REG_CMD			1
+#define   CHECK_REG_CMD			2
+
+#define RTSX_HDBAR			0x08
+#define   SG_INT			0x04
+#define   SG_END			0x02
+#define   SG_VALID			0x01
+#define   SG_NO_OP			0x00
+#define   SG_TRANS_DATA			(0x02 << 4)
+#define   SG_LINK_DESC			(0x03 << 4)
+#define RTSX_HDBCTLR			0x0C
+#define   SDMA_MODE			0x00
+#define   ADMA_MODE			(0x02 << 26)
+#define   STOP_DMA			(0x01 << 28)
+#define   TRIG_DMA			(0x01 << 31)
+
+#define RTSX_HAIMR			0x10
+#define   HAIMR_TRANS_START		(0x01 << 31)
+#define   HAIMR_READ			0x00
+#define   HAIMR_WRITE			(0x01 << 30)
+#define   HAIMR_READ_START		(HAIMR_TRANS_START | HAIMR_READ)
+#define   HAIMR_WRITE_START		(HAIMR_TRANS_START | HAIMR_WRITE)
+#define   HAIMR_TRANS_END			(HAIMR_TRANS_START)
+
+#define RTSX_BIPR			0x14
+#define   CMD_DONE_INT			(1 << 31)
+#define   DATA_DONE_INT			(1 << 30)
+#define   TRANS_OK_INT			(1 << 29)
+#define   TRANS_FAIL_INT		(1 << 28)
+#define   XD_INT			(1 << 27)
+#define   MS_INT			(1 << 26)
+#define   SD_INT			(1 << 25)
+#define   GPIO0_INT			(1 << 24)
+#define   OC_INT			(1 << 23)
+#define   SD_WRITE_PROTECT		(1 << 19)
+#define   XD_EXIST			(1 << 18)
+#define   MS_EXIST			(1 << 17)
+#define   SD_EXIST			(1 << 16)
+#define   DELINK_INT			GPIO0_INT
+#define   MS_OC_INT			(1 << 23)
+#define   SD_OC_INT			(1 << 22)
+
+#define CARD_INT		(XD_INT | MS_INT | SD_INT)
+#define NEED_COMPLETE_INT	(DATA_DONE_INT | TRANS_OK_INT | TRANS_FAIL_INT)
+#define RTSX_INT		(CMD_DONE_INT | NEED_COMPLETE_INT | \
+					CARD_INT | GPIO0_INT | OC_INT)
+#define CARD_EXIST		(XD_EXIST | MS_EXIST | SD_EXIST)
+
+#define RTSX_BIER			0x18
+#define   CMD_DONE_INT_EN		(1 << 31)
+#define   DATA_DONE_INT_EN		(1 << 30)
+#define   TRANS_OK_INT_EN		(1 << 29)
+#define   TRANS_FAIL_INT_EN		(1 << 28)
+#define   XD_INT_EN			(1 << 27)
+#define   MS_INT_EN			(1 << 26)
+#define   SD_INT_EN			(1 << 25)
+#define   GPIO0_INT_EN			(1 << 24)
+#define   OC_INT_EN			(1 << 23)
+#define   DELINK_INT_EN			GPIO0_INT_EN
+#define   MS_OC_INT_EN			(1 << 23)
+#define   SD_OC_INT_EN			(1 << 22)
+
+
+/*
+ * macros for easy use
+ */
+#define rtsx_pci_writel(pcr, reg, value) \
+	iowrite32(value, (pcr)->remap_addr + reg)
+#define rtsx_pci_readl(pcr, reg) \
+	ioread32((pcr)->remap_addr + reg)
+#define rtsx_pci_writew(pcr, reg, value) \
+	iowrite16(value, (pcr)->remap_addr + reg)
+#define rtsx_pci_readw(pcr, reg) \
+	ioread16((pcr)->remap_addr + reg)
+#define rtsx_pci_writeb(pcr, reg, value) \
+	iowrite8(value, (pcr)->remap_addr + reg)
+#define rtsx_pci_readb(pcr, reg) \
+	ioread8((pcr)->remap_addr + reg)
+
+#define rtsx_pci_read_config_byte(pcr, where, val) \
+	pci_read_config_byte((pcr)->pci, where, val)
+
+#define rtsx_pci_write_config_byte(pcr, where, val) \
+	pci_write_config_byte((pcr)->pci, where, val)
+
+#define rtsx_pci_read_config_dword(pcr, where, val) \
+	pci_read_config_dword((pcr)->pci, where, val)
+
+#define rtsx_pci_write_config_dword(pcr, where, val) \
+	pci_write_config_dword((pcr)->pci, where, val)
+
+#define STATE_TRANS_NONE		0
+#define STATE_TRANS_CMD			1
+#define STATE_TRANS_BUF			2
+#define STATE_TRANS_SG			3
+
+#define TRANS_NOT_READY			0
+#define TRANS_RESULT_OK			1
+#define TRANS_RESULT_FAIL		2
+#define TRANS_NO_DEVICE			3
+
+#define RTSX_RESV_BUF_LEN		4096
+#define HOST_CMDS_BUF_LEN		1024
+#define HOST_SG_TBL_BUF_LEN		(RTSX_RESV_BUF_LEN - HOST_CMDS_BUF_LEN)
+#define HOST_SG_TBL_ITEMS		(HOST_SG_TBL_BUF_LEN / 8)
+#define MAX_SG_ITEM_LEN			0x80000
+#define HOST_TO_DEVICE			0
+#define DEVICE_TO_HOST			1
+
+#define OUTPUT_3V3			0
+#define OUTPUT_1V8			1
+
+#define RTSX_PHASE_MAX			32
+#define RX_TUNING_CNT			3
+
+#define MS_CFG				0xFD40
+#define   SAMPLE_TIME_RISING		0x00
+#define   SAMPLE_TIME_FALLING		0x80
+#define   PUSH_TIME_DEFAULT		0x00
+#define   PUSH_TIME_ODD			0x40
+#define   NO_EXTEND_TOGGLE		0x00
+#define   EXTEND_TOGGLE_CHK		0x20
+#define   MS_BUS_WIDTH_1		0x00
+#define   MS_BUS_WIDTH_4		0x10
+#define   MS_BUS_WIDTH_8		0x18
+#define   MS_2K_SECTOR_MODE		0x04
+#define   MS_512_SECTOR_MODE		0x00
+#define   MS_TOGGLE_TIMEOUT_EN		0x00
+#define   MS_TOGGLE_TIMEOUT_DISEN	0x01
+#define MS_NO_CHECK_INT			0x02
+#define MS_TPC				0xFD41
+#define MS_TRANS_CFG			0xFD42
+#define   WAIT_INT			0x80
+#define   NO_WAIT_INT			0x00
+#define   NO_AUTO_READ_INT_REG		0x00
+#define   AUTO_READ_INT_REG		0x40
+#define   MS_CRC16_ERR			0x20
+#define   MS_RDY_TIMEOUT		0x10
+#define   MS_INT_CMDNK			0x08
+#define   MS_INT_BREQ			0x04
+#define   MS_INT_ERR			0x02
+#define   MS_INT_CED			0x01
+#define MS_TRANSFER			0xFD43
+#define   MS_TRANSFER_START		0x80
+#define   MS_TRANSFER_END		0x40
+#define   MS_TRANSFER_ERR		0x20
+#define   MS_BS_STATE			0x10
+#define   MS_TM_READ_BYTES		0x00
+#define   MS_TM_NORMAL_READ		0x01
+#define   MS_TM_WRITE_BYTES		0x04
+#define   MS_TM_NORMAL_WRITE		0x05
+#define   MS_TM_AUTO_READ		0x08
+#define   MS_TM_AUTO_WRITE		0x0C
+#define MS_INT_REG			0xFD44
+#define MS_BYTE_CNT			0xFD45
+#define MS_SECTOR_CNT_L			0xFD46
+#define MS_SECTOR_CNT_H			0xFD47
+#define MS_DBUS_H			0xFD48
+
+#define SD_CFG1				0xFDA0
+#define   SD_CLK_DIVIDE_0		0x00
+#define   SD_CLK_DIVIDE_256		0xC0
+#define   SD_CLK_DIVIDE_128		0x80
+#define   SD_BUS_WIDTH_1BIT		0x00
+#define   SD_BUS_WIDTH_4BIT		0x01
+#define   SD_BUS_WIDTH_8BIT		0x02
+#define   SD_ASYNC_FIFO_NOT_RST		0x10
+#define   SD_20_MODE			0x00
+#define   SD_DDR_MODE			0x04
+#define   SD_30_MODE			0x08
+#define   SD_CLK_DIVIDE_MASK		0xC0
+#define SD_CFG2				0xFDA1
+#define   SD_CALCULATE_CRC7		0x00
+#define   SD_NO_CALCULATE_CRC7		0x80
+#define   SD_CHECK_CRC16		0x00
+#define   SD_NO_CHECK_CRC16		0x40
+#define   SD_NO_CHECK_WAIT_CRC_TO	0x20
+#define   SD_WAIT_BUSY_END		0x08
+#define   SD_NO_WAIT_BUSY_END		0x00
+#define   SD_CHECK_CRC7			0x00
+#define   SD_NO_CHECK_CRC7		0x04
+#define   SD_RSP_LEN_0			0x00
+#define   SD_RSP_LEN_6			0x01
+#define   SD_RSP_LEN_17			0x02
+#define   SD_RSP_TYPE_R0		0x04
+#define   SD_RSP_TYPE_R1		0x01
+#define   SD_RSP_TYPE_R1b		0x09
+#define   SD_RSP_TYPE_R2		0x02
+#define   SD_RSP_TYPE_R3		0x05
+#define   SD_RSP_TYPE_R4		0x05
+#define   SD_RSP_TYPE_R5		0x01
+#define   SD_RSP_TYPE_R6		0x01
+#define   SD_RSP_TYPE_R7		0x01
+#define SD_CFG3				0xFDA2
+#define   SD_RSP_80CLK_TIMEOUT_EN	0x01
+
+#define SD_STAT1			0xFDA3
+#define   SD_CRC7_ERR			0x80
+#define   SD_CRC16_ERR			0x40
+#define   SD_CRC_WRITE_ERR		0x20
+#define   SD_CRC_WRITE_ERR_MASK		0x1C
+#define   GET_CRC_TIME_OUT		0x02
+#define   SD_TUNING_COMPARE_ERR		0x01
+#define SD_STAT2			0xFDA4
+#define   SD_RSP_80CLK_TIMEOUT		0x01
+
+#define SD_BUS_STAT			0xFDA5
+#define   SD_CLK_TOGGLE_EN		0x80
+#define   SD_CLK_FORCE_STOP		0x40
+#define   SD_DAT3_STATUS		0x10
+#define   SD_DAT2_STATUS		0x08
+#define   SD_DAT1_STATUS		0x04
+#define   SD_DAT0_STATUS		0x02
+#define   SD_CMD_STATUS			0x01
+#define SD_PAD_CTL			0xFDA6
+#define   SD_IO_USING_1V8		0x80
+#define   SD_IO_USING_3V3		0x7F
+#define   TYPE_A_DRIVING		0x00
+#define   TYPE_B_DRIVING		0x01
+#define   TYPE_C_DRIVING		0x02
+#define   TYPE_D_DRIVING		0x03
+#define SD_SAMPLE_POINT_CTL		0xFDA7
+#define   DDR_FIX_RX_DAT		0x00
+#define   DDR_VAR_RX_DAT		0x80
+#define   DDR_FIX_RX_DAT_EDGE		0x00
+#define   DDR_FIX_RX_DAT_14_DELAY	0x40
+#define   DDR_FIX_RX_CMD		0x00
+#define   DDR_VAR_RX_CMD		0x20
+#define   DDR_FIX_RX_CMD_POS_EDGE	0x00
+#define   DDR_FIX_RX_CMD_14_DELAY	0x10
+#define   SD20_RX_POS_EDGE		0x00
+#define   SD20_RX_14_DELAY		0x08
+#define SD20_RX_SEL_MASK		0x08
+#define SD_PUSH_POINT_CTL		0xFDA8
+#define   DDR_FIX_TX_CMD_DAT		0x00
+#define   DDR_VAR_TX_CMD_DAT		0x80
+#define   DDR_FIX_TX_DAT_14_TSU		0x00
+#define   DDR_FIX_TX_DAT_12_TSU		0x40
+#define   DDR_FIX_TX_CMD_NEG_EDGE	0x00
+#define   DDR_FIX_TX_CMD_14_AHEAD	0x20
+#define   SD20_TX_NEG_EDGE		0x00
+#define   SD20_TX_14_AHEAD		0x10
+#define   SD20_TX_SEL_MASK		0x10
+#define   DDR_VAR_SDCLK_POL_SWAP	0x01
+#define SD_CMD0				0xFDA9
+#define   SD_CMD_START			0x40
+#define SD_CMD1				0xFDAA
+#define SD_CMD2				0xFDAB
+#define SD_CMD3				0xFDAC
+#define SD_CMD4				0xFDAD
+#define SD_CMD5				0xFDAE
+#define SD_BYTE_CNT_L			0xFDAF
+#define SD_BYTE_CNT_H			0xFDB0
+#define SD_BLOCK_CNT_L			0xFDB1
+#define SD_BLOCK_CNT_H			0xFDB2
+#define SD_TRANSFER			0xFDB3
+#define   SD_TRANSFER_START		0x80
+#define   SD_TRANSFER_END		0x40
+#define   SD_STAT_IDLE			0x20
+#define   SD_TRANSFER_ERR		0x10
+#define   SD_TM_NORMAL_WRITE		0x00
+#define   SD_TM_AUTO_WRITE_3		0x01
+#define   SD_TM_AUTO_WRITE_4		0x02
+#define   SD_TM_AUTO_READ_3		0x05
+#define   SD_TM_AUTO_READ_4		0x06
+#define   SD_TM_CMD_RSP			0x08
+#define   SD_TM_AUTO_WRITE_1		0x09
+#define   SD_TM_AUTO_WRITE_2		0x0A
+#define   SD_TM_NORMAL_READ		0x0C
+#define   SD_TM_AUTO_READ_1		0x0D
+#define   SD_TM_AUTO_READ_2		0x0E
+#define   SD_TM_AUTO_TUNING		0x0F
+#define SD_CMD_STATE			0xFDB5
+#define   SD_CMD_IDLE			0x80
+
+#define SD_DATA_STATE			0xFDB6
+#define   SD_DATA_IDLE			0x80
+
+#define SRCTL				0xFC13
+
+#define DCM_DRP_CTL			0xFC23
+#define   DCM_RESET			0x08
+#define   DCM_LOCKED			0x04
+#define   DCM_208M			0x00
+#define   DCM_TX			0x01
+#define   DCM_RX			0x02
+#define DCM_DRP_TRIG			0xFC24
+#define   DRP_START			0x80
+#define   DRP_DONE			0x40
+#define DCM_DRP_CFG			0xFC25
+#define   DRP_WRITE			0x80
+#define   DRP_READ			0x00
+#define   DCM_WRITE_ADDRESS_50		0x50
+#define   DCM_WRITE_ADDRESS_51		0x51
+#define   DCM_READ_ADDRESS_00		0x00
+#define   DCM_READ_ADDRESS_51		0x51
+#define DCM_DRP_WR_DATA_L		0xFC26
+#define DCM_DRP_WR_DATA_H		0xFC27
+#define DCM_DRP_RD_DATA_L		0xFC28
+#define DCM_DRP_RD_DATA_H		0xFC29
+#define SD_VPCLK0_CTL			0xFC2A
+#define SD_VPCLK1_CTL			0xFC2B
+#define   PHASE_SELECT_MASK		0x1F
+#define SD_DCMPS0_CTL			0xFC2C
+#define SD_DCMPS1_CTL			0xFC2D
+#define SD_VPTX_CTL			SD_VPCLK0_CTL
+#define SD_VPRX_CTL			SD_VPCLK1_CTL
+#define   PHASE_CHANGE			0x80
+#define   PHASE_NOT_RESET		0x40
+#define SD_DCMPS_TX_CTL			SD_DCMPS0_CTL
+#define SD_DCMPS_RX_CTL			SD_DCMPS1_CTL
+#define   DCMPS_CHANGE			0x80
+#define   DCMPS_CHANGE_DONE		0x40
+#define   DCMPS_ERROR			0x20
+#define   DCMPS_CURRENT_PHASE		0x1F
+#define CARD_CLK_SOURCE			0xFC2E
+#define   CRC_FIX_CLK			(0x00 << 0)
+#define   CRC_VAR_CLK0			(0x01 << 0)
+#define   CRC_VAR_CLK1			(0x02 << 0)
+#define   SD30_FIX_CLK			(0x00 << 2)
+#define   SD30_VAR_CLK0			(0x01 << 2)
+#define   SD30_VAR_CLK1			(0x02 << 2)
+#define   SAMPLE_FIX_CLK		(0x00 << 4)
+#define   SAMPLE_VAR_CLK0		(0x01 << 4)
+#define   SAMPLE_VAR_CLK1		(0x02 << 4)
+#define CARD_PWR_CTL			0xFD50
+#define   PMOS_STRG_MASK		0x10
+#define   PMOS_STRG_800mA		0x10
+#define   PMOS_STRG_400mA		0x00
+#define   SD_POWER_OFF			0x03
+#define   SD_PARTIAL_POWER_ON		0x01
+#define   SD_POWER_ON			0x00
+#define   SD_POWER_MASK			0x03
+#define   MS_POWER_OFF			0x0C
+#define   MS_PARTIAL_POWER_ON		0x04
+#define   MS_POWER_ON			0x00
+#define   MS_POWER_MASK			0x0C
+#define   BPP_POWER_OFF			0x0F
+#define   BPP_POWER_5_PERCENT_ON	0x0E
+#define   BPP_POWER_10_PERCENT_ON	0x0C
+#define   BPP_POWER_15_PERCENT_ON	0x08
+#define   BPP_POWER_ON			0x00
+#define   BPP_POWER_MASK		0x0F
+#define   SD_VCC_PARTIAL_POWER_ON	0x02
+#define   SD_VCC_POWER_ON		0x00
+#define CARD_CLK_SWITCH			0xFD51
+#define RTL8411B_PACKAGE_MODE		0xFD51
+#define CARD_SHARE_MODE			0xFD52
+#define   CARD_SHARE_MASK		0x0F
+#define   CARD_SHARE_MULTI_LUN		0x00
+#define   CARD_SHARE_NORMAL		0x00
+#define   CARD_SHARE_48_SD		0x04
+#define   CARD_SHARE_48_MS		0x08
+#define   CARD_SHARE_BAROSSA_SD		0x01
+#define   CARD_SHARE_BAROSSA_MS		0x02
+#define CARD_DRIVE_SEL			0xFD53
+#define   MS_DRIVE_8mA			(0x01 << 6)
+#define   MMC_DRIVE_8mA			(0x01 << 4)
+#define   XD_DRIVE_8mA			(0x01 << 2)
+#define   GPIO_DRIVE_8mA		0x01
+#define RTS5209_CARD_DRIVE_DEFAULT	(MS_DRIVE_8mA | MMC_DRIVE_8mA |\
+					XD_DRIVE_8mA | GPIO_DRIVE_8mA)
+#define RTL8411_CARD_DRIVE_DEFAULT	(MS_DRIVE_8mA | MMC_DRIVE_8mA |\
+					XD_DRIVE_8mA)
+#define RTSX_CARD_DRIVE_DEFAULT		(MS_DRIVE_8mA | GPIO_DRIVE_8mA)
+
+#define CARD_STOP			0xFD54
+#define   SPI_STOP			0x01
+#define   XD_STOP			0x02
+#define   SD_STOP			0x04
+#define   MS_STOP			0x08
+#define   SPI_CLR_ERR			0x10
+#define   XD_CLR_ERR			0x20
+#define   SD_CLR_ERR			0x40
+#define   MS_CLR_ERR			0x80
+#define CARD_OE				0xFD55
+#define   SD_OUTPUT_EN			0x04
+#define   MS_OUTPUT_EN			0x08
+#define CARD_AUTO_BLINK			0xFD56
+#define CARD_GPIO_DIR			0xFD57
+#define CARD_GPIO			0xFD58
+#define CARD_DATA_SOURCE		0xFD5B
+#define   PINGPONG_BUFFER		0x01
+#define   RING_BUFFER			0x00
+#define SD30_CLK_DRIVE_SEL		0xFD5A
+#define   DRIVER_TYPE_A			0x05
+#define   DRIVER_TYPE_B			0x03
+#define   DRIVER_TYPE_C			0x02
+#define   DRIVER_TYPE_D			0x01
+#define CARD_SELECT			0xFD5C
+#define   SD_MOD_SEL			2
+#define   MS_MOD_SEL			3
+#define SD30_DRIVE_SEL			0xFD5E
+#define   CFG_DRIVER_TYPE_A		0x02
+#define   CFG_DRIVER_TYPE_B		0x03
+#define   CFG_DRIVER_TYPE_C		0x01
+#define   CFG_DRIVER_TYPE_D		0x00
+#define SD30_CMD_DRIVE_SEL		0xFD5E
+#define SD30_DAT_DRIVE_SEL		0xFD5F
+#define CARD_CLK_EN			0xFD69
+#define   SD_CLK_EN			0x04
+#define   MS_CLK_EN			0x08
+#define SDIO_CTRL			0xFD6B
+#define CD_PAD_CTL			0xFD73
+#define   CD_DISABLE_MASK		0x07
+#define   MS_CD_DISABLE			0x04
+#define   SD_CD_DISABLE			0x02
+#define   XD_CD_DISABLE			0x01
+#define   CD_DISABLE			0x07
+#define   CD_ENABLE			0x00
+#define   MS_CD_EN_ONLY			0x03
+#define   SD_CD_EN_ONLY			0x05
+#define   XD_CD_EN_ONLY			0x06
+#define   FORCE_CD_LOW_MASK		0x38
+#define   FORCE_CD_XD_LOW		0x08
+#define   FORCE_CD_SD_LOW		0x10
+#define   FORCE_CD_MS_LOW		0x20
+#define   CD_AUTO_DISABLE		0x40
+#define FPDCTL				0xFC00
+#define   SSC_POWER_DOWN		0x01
+#define   SD_OC_POWER_DOWN		0x02
+#define   ALL_POWER_DOWN		0x07
+#define   OC_POWER_DOWN			0x06
+#define PDINFO				0xFC01
+
+#define CLK_CTL				0xFC02
+#define   CHANGE_CLK			0x01
+#define   CLK_LOW_FREQ			0x01
+
+#define CLK_DIV				0xFC03
+#define   CLK_DIV_1			0x01
+#define   CLK_DIV_2			0x02
+#define   CLK_DIV_4			0x03
+#define   CLK_DIV_8			0x04
+#define CLK_SEL				0xFC04
+
+#define SSC_DIV_N_0			0xFC0F
+#define SSC_DIV_N_1			0xFC10
+#define SSC_CTL1			0xFC11
+#define    SSC_RSTB			0x80
+#define    SSC_8X_EN			0x40
+#define    SSC_FIX_FRAC			0x20
+#define    SSC_SEL_1M			0x00
+#define    SSC_SEL_2M			0x08
+#define    SSC_SEL_4M			0x10
+#define    SSC_SEL_8M			0x18
+#define SSC_CTL2			0xFC12
+#define    SSC_DEPTH_MASK		0x07
+#define    SSC_DEPTH_DISALBE		0x00
+#define    SSC_DEPTH_4M			0x01
+#define    SSC_DEPTH_2M			0x02
+#define    SSC_DEPTH_1M			0x03
+#define    SSC_DEPTH_500K		0x04
+#define    SSC_DEPTH_250K		0x05
+#define RCCTL				0xFC14
+
+#define FPGA_PULL_CTL			0xFC1D
+#define OLT_LED_CTL			0xFC1E
+#define GPIO_CTL			0xFC1F
+
+#define LDO_CTL				0xFC1E
+#define   BPP_ASIC_1V7			0x00
+#define   BPP_ASIC_1V8			0x01
+#define   BPP_ASIC_1V9			0x02
+#define   BPP_ASIC_2V0			0x03
+#define   BPP_ASIC_2V7			0x04
+#define   BPP_ASIC_2V8			0x05
+#define   BPP_ASIC_3V2			0x06
+#define   BPP_ASIC_3V3			0x07
+#define   BPP_REG_TUNED18		0x07
+#define   BPP_TUNED18_SHIFT_8402	5
+#define   BPP_TUNED18_SHIFT_8411	4
+#define   BPP_PAD_MASK			0x04
+#define   BPP_PAD_3V3			0x04
+#define   BPP_PAD_1V8			0x00
+#define   BPP_LDO_POWB			0x03
+#define   BPP_LDO_ON			0x00
+#define   BPP_LDO_SUSPEND		0x02
+#define   BPP_LDO_OFF			0x03
+#define SYS_VER				0xFC32
+
+#define CARD_PULL_CTL1			0xFD60
+#define CARD_PULL_CTL2			0xFD61
+#define CARD_PULL_CTL3			0xFD62
+#define CARD_PULL_CTL4			0xFD63
+#define CARD_PULL_CTL5			0xFD64
+#define CARD_PULL_CTL6			0xFD65
+
+/* PCI Express Related Registers */
+#define IRQEN0				0xFE20
+#define IRQSTAT0			0xFE21
+#define    DMA_DONE_INT			0x80
+#define    SUSPEND_INT			0x40
+#define    LINK_RDY_INT			0x20
+#define    LINK_DOWN_INT		0x10
+#define IRQEN1				0xFE22
+#define IRQSTAT1			0xFE23
+#define TLPRIEN				0xFE24
+#define TLPRISTAT			0xFE25
+#define TLPTIEN				0xFE26
+#define TLPTISTAT			0xFE27
+#define DMATC0				0xFE28
+#define DMATC1				0xFE29
+#define DMATC2				0xFE2A
+#define DMATC3				0xFE2B
+#define DMACTL				0xFE2C
+#define   DMA_RST			0x80
+#define   DMA_BUSY			0x04
+#define   DMA_DIR_TO_CARD		0x00
+#define   DMA_DIR_FROM_CARD		0x02
+#define   DMA_EN			0x01
+#define   DMA_128			(0 << 4)
+#define   DMA_256			(1 << 4)
+#define   DMA_512			(2 << 4)
+#define   DMA_1024			(3 << 4)
+#define   DMA_PACK_SIZE_MASK		0x30
+#define BCTL				0xFE2D
+#define RBBC0				0xFE2E
+#define RBBC1				0xFE2F
+#define RBDAT				0xFE30
+#define RBCTL				0xFE34
+#define CFGADDR0			0xFE35
+#define CFGADDR1			0xFE36
+#define CFGDATA0			0xFE37
+#define CFGDATA1			0xFE38
+#define CFGDATA2			0xFE39
+#define CFGDATA3			0xFE3A
+#define CFGRWCTL			0xFE3B
+#define PHYRWCTL			0xFE3C
+#define PHYDATA0			0xFE3D
+#define PHYDATA1			0xFE3E
+#define PHYADDR				0xFE3F
+#define MSGRXDATA0			0xFE40
+#define MSGRXDATA1			0xFE41
+#define MSGRXDATA2			0xFE42
+#define MSGRXDATA3			0xFE43
+#define MSGTXDATA0			0xFE44
+#define MSGTXDATA1			0xFE45
+#define MSGTXDATA2			0xFE46
+#define MSGTXDATA3			0xFE47
+#define MSGTXCTL			0xFE48
+#define LTR_CTL				0xFE4A
+#define LTR_TX_EN_MASK		BIT(7)
+#define LTR_TX_EN_1			BIT(7)
+#define LTR_TX_EN_0			0
+#define LTR_LATENCY_MODE_MASK		BIT(6)
+#define LTR_LATENCY_MODE_HW		0
+#define LTR_LATENCY_MODE_SW		BIT(6)
+#define OBFF_CFG			0xFE4C
+
+#define CDRESUMECTL			0xFE52
+#define WAKE_SEL_CTL			0xFE54
+#define PCLK_CTL			0xFE55
+#define   PCLK_MODE_SEL			0x20
+#define PME_FORCE_CTL			0xFE56
+
+#define ASPM_FORCE_CTL			0xFE57
+#define   FORCE_ASPM_CTL0		0x10
+#define   FORCE_ASPM_VAL_MASK		0x03
+#define   FORCE_ASPM_L1_EN		0x02
+#define   FORCE_ASPM_L0_EN		0x01
+#define   FORCE_ASPM_NO_ASPM		0x00
+#define PM_CLK_FORCE_CTL		0xFE58
+#define FUNC_FORCE_CTL			0xFE59
+#define   FUNC_FORCE_UPME_XMT_DBG	0x02
+#define PERST_GLITCH_WIDTH		0xFE5C
+#define CHANGE_LINK_STATE		0xFE5B
+#define RESET_LOAD_REG			0xFE5E
+#define EFUSE_CONTENT			0xFE5F
+#define HOST_SLEEP_STATE		0xFE60
+#define   HOST_ENTER_S1			1
+#define   HOST_ENTER_S3			2
+
+#define SDIO_CFG			0xFE70
+#define PM_EVENT_DEBUG			0xFE71
+#define   PME_DEBUG_0			0x08
+#define NFTS_TX_CTRL			0xFE72
+
+#define PWR_GATE_CTRL			0xFE75
+#define   PWR_GATE_EN			0x01
+#define   LDO3318_PWR_MASK		0x06
+#define   LDO_ON			0x00
+#define   LDO_SUSPEND			0x04
+#define   LDO_OFF			0x06
+#define PWD_SUSPEND_EN			0xFE76
+#define LDO_PWR_SEL			0xFE78
+
+#define L1SUB_CONFIG1			0xFE8D
+#define L1SUB_CONFIG2			0xFE8E
+#define   L1SUB_AUTO_CFG		0x02
+#define L1SUB_CONFIG3			0xFE8F
+#define   L1OFF_MBIAS2_EN_5250		BIT(7)
+
+#define DUMMY_REG_RESET_0		0xFE90
+
+#define AUTOLOAD_CFG_BASE		0xFF00
+#define PETXCFG				0xFF03
+#define FORCE_CLKREQ_DELINK_MASK	BIT(7)
+#define FORCE_CLKREQ_LOW	0x80
+#define FORCE_CLKREQ_HIGH	0x00
+
+#define PM_CTRL1			0xFF44
+#define   CD_RESUME_EN_MASK		0xF0
+
+#define PM_CTRL2			0xFF45
+#define PM_CTRL3			0xFF46
+#define   SDIO_SEND_PME_EN		0x80
+#define   FORCE_RC_MODE_ON		0x40
+#define   FORCE_RX50_LINK_ON		0x20
+#define   D3_DELINK_MODE_EN		0x10
+#define   USE_PESRTB_CTL_DELINK		0x08
+#define   DELAY_PIN_WAKE		0x04
+#define   RESET_PIN_WAKE		0x02
+#define   PM_WAKE_EN			0x01
+#define PM_CTRL4			0xFF47
+
+/* Memory mapping */
+#define SRAM_BASE			0xE600
+#define RBUF_BASE			0xF400
+#define PPBUF_BASE1			0xF800
+#define PPBUF_BASE2			0xFA00
+#define IMAGE_FLAG_ADDR0		0xCE80
+#define IMAGE_FLAG_ADDR1		0xCE81
+
+#define RREF_CFG			0xFF6C
+#define   RREF_VBGSEL_MASK		0x38
+#define   RREF_VBGSEL_1V25		0x28
+
+#define OOBS_CONFIG			0xFF6E
+#define   OOBS_AUTOK_DIS		0x80
+#define   OOBS_VAL_MASK			0x1F
+
+#define LDO_DV18_CFG			0xFF70
+#define   LDO_DV18_SR_MASK		0xC0
+#define   LDO_DV18_SR_DF		0x40
+
+#define LDO_CONFIG2			0xFF71
+#define   LDO_D3318_MASK		0x07
+#define   LDO_D3318_33V			0x07
+#define   LDO_D3318_18V			0x02
+
+#define LDO_VCC_CFG0			0xFF72
+#define   LDO_VCC_LMTVTH_MASK		0x30
+#define   LDO_VCC_LMTVTH_2A		0x10
+
+#define LDO_VCC_CFG1			0xFF73
+#define   LDO_VCC_REF_TUNE_MASK		0x30
+#define   LDO_VCC_REF_1V2		0x20
+#define   LDO_VCC_TUNE_MASK		0x07
+#define   LDO_VCC_1V8			0x04
+#define   LDO_VCC_3V3			0x07
+#define   LDO_VCC_LMT_EN		0x08
+
+#define LDO_VIO_CFG			0xFF75
+#define   LDO_VIO_SR_MASK		0xC0
+#define   LDO_VIO_SR_DF			0x40
+#define   LDO_VIO_REF_TUNE_MASK		0x30
+#define   LDO_VIO_REF_1V2		0x20
+#define   LDO_VIO_TUNE_MASK		0x07
+#define   LDO_VIO_1V7			0x03
+#define   LDO_VIO_1V8			0x04
+#define   LDO_VIO_3V3			0x07
+
+#define LDO_DV12S_CFG			0xFF76
+#define   LDO_REF12_TUNE_MASK		0x18
+#define   LDO_REF12_TUNE_DF		0x10
+#define   LDO_D12_TUNE_MASK		0x07
+#define   LDO_D12_TUNE_DF		0x04
+
+#define LDO_AV12S_CFG			0xFF77
+#define   LDO_AV12S_TUNE_MASK		0x07
+#define   LDO_AV12S_TUNE_DF		0x04
+
+#define SD40_LDO_CTL1			0xFE7D
+#define   SD40_VIO_TUNE_MASK		0x70
+#define   SD40_VIO_TUNE_1V7		0x30
+#define   SD_VIO_LDO_1V8		0x40
+#define   SD_VIO_LDO_3V3		0x70
+
+/* Phy register */
+#define PHY_PCR				0x00
+#define   PHY_PCR_FORCE_CODE		0xB000
+#define   PHY_PCR_OOBS_CALI_50		0x0800
+#define   PHY_PCR_OOBS_VCM_08		0x0200
+#define   PHY_PCR_OOBS_SEN_90		0x0040
+#define   PHY_PCR_RSSI_EN		0x0002
+#define   PHY_PCR_RX10K			0x0001
+
+#define PHY_RCR0			0x01
+#define PHY_RCR1			0x02
+#define   PHY_RCR1_ADP_TIME_4		0x0400
+#define   PHY_RCR1_VCO_COARSE		0x001F
+#define   PHY_RCR1_INIT_27S		0x0A1F
+#define PHY_SSCCR2			0x02
+#define   PHY_SSCCR2_PLL_NCODE		0x0A00
+#define   PHY_SSCCR2_TIME0		0x001C
+#define   PHY_SSCCR2_TIME2_WIDTH	0x0003
+
+#define PHY_RCR2			0x03
+#define   PHY_RCR2_EMPHASE_EN		0x8000
+#define   PHY_RCR2_NADJR		0x4000
+#define   PHY_RCR2_CDR_SR_2		0x0100
+#define   PHY_RCR2_FREQSEL_12		0x0040
+#define   PHY_RCR2_CDR_SC_12P		0x0010
+#define   PHY_RCR2_CALIB_LATE		0x0002
+#define   PHY_RCR2_INIT_27S		0xC152
+#define PHY_SSCCR3			0x03
+#define   PHY_SSCCR3_STEP_IN		0x2740
+#define   PHY_SSCCR3_CHECK_DELAY	0x0008
+#define _PHY_ANA03			0x03
+#define   _PHY_ANA03_TIMER_MAX		0x2700
+#define   _PHY_ANA03_OOBS_DEB_EN	0x0040
+#define   _PHY_CMU_DEBUG_EN		0x0008
+
+#define PHY_RTCR			0x04
+#define PHY_RDR				0x05
+#define   PHY_RDR_RXDSEL_1_9		0x4000
+#define   PHY_SSC_AUTO_PWD		0x0600
+#define PHY_TCR0			0x06
+#define PHY_TCR1			0x07
+#define PHY_TUNE			0x08
+#define   PHY_TUNE_TUNEREF_1_0		0x4000
+#define   PHY_TUNE_VBGSEL_1252		0x0C00
+#define   PHY_TUNE_SDBUS_33		0x0200
+#define   PHY_TUNE_TUNED18		0x01C0
+#define   PHY_TUNE_TUNED12		0X0020
+#define   PHY_TUNE_TUNEA12		0x0004
+#define   PHY_TUNE_VOLTAGE_MASK		0xFC3F
+#define   PHY_TUNE_VOLTAGE_3V3		0x03C0
+#define   PHY_TUNE_D18_1V8		0x0100
+#define   PHY_TUNE_D18_1V7		0x0080
+#define PHY_ANA08			0x08
+#define   PHY_ANA08_RX_EQ_DCGAIN	0x5000
+#define   PHY_ANA08_SEL_RX_EN		0x0400
+#define   PHY_ANA08_RX_EQ_VAL		0x03C0
+#define   PHY_ANA08_SCP			0x0020
+#define   PHY_ANA08_SEL_IPI		0x0004
+
+#define PHY_IMR				0x09
+#define PHY_BPCR			0x0A
+#define   PHY_BPCR_IBRXSEL		0x0400
+#define   PHY_BPCR_IBTXSEL		0x0100
+#define   PHY_BPCR_IB_FILTER		0x0080
+#define   PHY_BPCR_CMIRROR_EN		0x0040
+
+#define PHY_BIST			0x0B
+#define PHY_RAW_L			0x0C
+#define PHY_RAW_H			0x0D
+#define PHY_RAW_DATA			0x0E
+#define PHY_HOST_CLK_CTRL		0x0F
+#define PHY_DMR				0x10
+#define PHY_BACR			0x11
+#define   PHY_BACR_BASIC_MASK		0xFFF3
+#define PHY_IER				0x12
+#define PHY_BCSR			0x13
+#define PHY_BPR				0x14
+#define PHY_BPNR2			0x15
+#define PHY_BPNR			0x16
+#define PHY_BRNR2			0x17
+#define PHY_BENR			0x18
+#define PHY_REV				0x19
+#define   PHY_REV_RESV			0xE000
+#define   PHY_REV_RXIDLE_LATCHED	0x1000
+#define   PHY_REV_P1_EN			0x0800
+#define   PHY_REV_RXIDLE_EN		0x0400
+#define   PHY_REV_CLKREQ_TX_EN		0x0200
+#define   PHY_REV_CLKREQ_RX_EN		0x0100
+#define   PHY_REV_CLKREQ_DT_1_0		0x0040
+#define   PHY_REV_STOP_CLKRD		0x0020
+#define   PHY_REV_RX_PWST		0x0008
+#define   PHY_REV_STOP_CLKWR		0x0004
+#define _PHY_REV0			0x19
+#define   _PHY_REV0_FILTER_OUT		0x3800
+#define   _PHY_REV0_CDR_BYPASS_PFD	0x0100
+#define   _PHY_REV0_CDR_RX_IDLE_BYPASS	0x0002
+
+#define PHY_FLD0			0x1A
+#define PHY_ANA1A			0x1A
+#define   PHY_ANA1A_TXR_LOOPBACK	0x2000
+#define   PHY_ANA1A_RXT_BIST		0x0500
+#define   PHY_ANA1A_TXR_BIST		0x0040
+#define   PHY_ANA1A_REV			0x0006
+#define   PHY_FLD0_INIT_27S		0x2546
+#define PHY_FLD1			0x1B
+#define PHY_FLD2			0x1C
+#define PHY_FLD3			0x1D
+#define   PHY_FLD3_TIMER_4		0x0800
+#define   PHY_FLD3_TIMER_6		0x0020
+#define   PHY_FLD3_RXDELINK		0x0004
+#define   PHY_FLD3_INIT_27S		0x0004
+#define PHY_ANA1D			0x1D
+#define   PHY_ANA1D_DEBUG_ADDR		0x0004
+#define _PHY_FLD0			0x1D
+#define   _PHY_FLD0_CLK_REQ_20C		0x8000
+#define   _PHY_FLD0_RX_IDLE_EN		0x1000
+#define   _PHY_FLD0_BIT_ERR_RSTN	0x0800
+#define   _PHY_FLD0_BER_COUNT		0x01E0
+#define   _PHY_FLD0_BER_TIMER		0x001E
+#define   _PHY_FLD0_CHECK_EN		0x0001
+
+#define PHY_FLD4			0x1E
+#define   PHY_FLD4_FLDEN_SEL		0x4000
+#define   PHY_FLD4_REQ_REF		0x2000
+#define   PHY_FLD4_RXAMP_OFF		0x1000
+#define   PHY_FLD4_REQ_ADDA		0x0800
+#define   PHY_FLD4_BER_COUNT		0x00E0
+#define   PHY_FLD4_BER_TIMER		0x000A
+#define   PHY_FLD4_BER_CHK_EN		0x0001
+#define   PHY_FLD4_INIT_27S		0x5C7F
+#define PHY_DIG1E			0x1E
+#define   PHY_DIG1E_REV			0x4000
+#define   PHY_DIG1E_D0_X_D1		0x1000
+#define   PHY_DIG1E_RX_ON_HOST		0x0800
+#define   PHY_DIG1E_RCLK_REF_HOST	0x0400
+#define   PHY_DIG1E_RCLK_TX_EN_KEEP	0x0040
+#define   PHY_DIG1E_RCLK_TX_TERM_KEEP	0x0020
+#define   PHY_DIG1E_RCLK_RX_EIDLE_ON	0x0010
+#define   PHY_DIG1E_TX_TERM_KEEP	0x0008
+#define   PHY_DIG1E_RX_TERM_KEEP	0x0004
+#define   PHY_DIG1E_TX_EN_KEEP		0x0002
+#define   PHY_DIG1E_RX_EN_KEEP		0x0001
+#define PHY_DUM_REG			0x1F
+
+#define PCR_ASPM_SETTING_REG1		0x160
+#define PCR_ASPM_SETTING_REG2		0x168
+
+#define PCR_SETTING_REG1		0x724
+#define PCR_SETTING_REG2		0x814
+#define PCR_SETTING_REG3		0x747
+
+#define rtsx_pci_init_cmd(pcr)		((pcr)->ci = 0)
+
+#define RTS5227_DEVICE_ID		0x5227
+#define RTS_MAX_TIMES_FREQ_REDUCTION	8
+
+struct rtsx_pcr;
+
+struct pcr_handle {
+	struct rtsx_pcr			*pcr;
+};
+
+struct pcr_ops {
+	int (*write_phy)(struct rtsx_pcr *pcr, u8 addr, u16 val);
+	int (*read_phy)(struct rtsx_pcr *pcr, u8 addr, u16 *val);
+	int		(*extra_init_hw)(struct rtsx_pcr *pcr);
+	int		(*optimize_phy)(struct rtsx_pcr *pcr);
+	int		(*turn_on_led)(struct rtsx_pcr *pcr);
+	int		(*turn_off_led)(struct rtsx_pcr *pcr);
+	int		(*enable_auto_blink)(struct rtsx_pcr *pcr);
+	int		(*disable_auto_blink)(struct rtsx_pcr *pcr);
+	int		(*card_power_on)(struct rtsx_pcr *pcr, int card);
+	int		(*card_power_off)(struct rtsx_pcr *pcr, int card);
+	int		(*switch_output_voltage)(struct rtsx_pcr *pcr,
+						u8 voltage);
+	unsigned int	(*cd_deglitch)(struct rtsx_pcr *pcr);
+	int		(*conv_clk_and_div_n)(int clk, int dir);
+	void		(*fetch_vendor_settings)(struct rtsx_pcr *pcr);
+	void		(*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
+
+	void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
+	int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency);
+	int (*set_l1off_sub)(struct rtsx_pcr *pcr, u8 val);
+	void (*set_l1off_cfg_sub_d0)(struct rtsx_pcr *pcr, int active);
+	void (*full_on)(struct rtsx_pcr *pcr);
+	void (*power_saving)(struct rtsx_pcr *pcr);
+};
+
+enum PDEV_STAT  {PDEV_STAT_IDLE, PDEV_STAT_RUN};
+
+#define ASPM_L1_1_EN_MASK		BIT(3)
+#define ASPM_L1_2_EN_MASK		BIT(2)
+#define PM_L1_1_EN_MASK		BIT(1)
+#define PM_L1_2_EN_MASK		BIT(0)
+
+#define ASPM_L1_1_EN			BIT(0)
+#define ASPM_L1_2_EN			BIT(1)
+#define PM_L1_1_EN				BIT(2)
+#define PM_L1_2_EN				BIT(3)
+#define LTR_L1SS_PWR_GATE_EN	BIT(4)
+#define L1_SNOOZE_TEST_EN		BIT(5)
+#define LTR_L1SS_PWR_GATE_CHECK_CARD_EN	BIT(6)
+
+enum dev_aspm_mode {
+	DEV_ASPM_DYNAMIC,
+	DEV_ASPM_BACKDOOR,
+	DEV_ASPM_STATIC,
+	DEV_ASPM_DISABLE,
+};
+
+/*
+ * struct rtsx_cr_option  - card reader option
+ * @dev_flags: device flags
+ * @force_clkreq_0: force clock request
+ * @ltr_en: enable ltr mode flag
+ * @ltr_enabled: ltr mode in configure space flag
+ * @ltr_active: ltr mode status
+ * @ltr_active_latency: ltr mode active latency
+ * @ltr_idle_latency: ltr mode idle latency
+ * @ltr_l1off_latency: ltr mode l1off latency
+ * @dev_aspm_mode: device aspm mode
+ * @l1_snooze_delay: l1 snooze delay
+ * @ltr_l1off_sspwrgate: ltr l1off sspwrgate
+ * @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate
+ */
+struct rtsx_cr_option {
+	u32 dev_flags;
+	bool force_clkreq_0;
+	bool ltr_en;
+	bool ltr_enabled;
+	bool ltr_active;
+	u32 ltr_active_latency;
+	u32 ltr_idle_latency;
+	u32 ltr_l1off_latency;
+	enum dev_aspm_mode dev_aspm_mode;
+	u32 l1_snooze_delay;
+	u8 ltr_l1off_sspwrgate;
+	u8 ltr_l1off_snooze_sspwrgate;
+};
+
+#define rtsx_set_dev_flag(cr, flag) \
+	((cr)->option.dev_flags |= (flag))
+#define rtsx_clear_dev_flag(cr, flag) \
+	((cr)->option.dev_flags &= ~(flag))
+#define rtsx_check_dev_flag(cr, flag) \
+	((cr)->option.dev_flags & (flag))
+
+struct rtsx_pcr {
+	struct pci_dev			*pci;
+	unsigned int			id;
+	int				pcie_cap;
+	struct rtsx_cr_option	option;
+
+	/* pci resources */
+	unsigned long			addr;
+	void __iomem			*remap_addr;
+	int				irq;
+
+	/* host reserved buffer */
+	void				*rtsx_resv_buf;
+	dma_addr_t			rtsx_resv_buf_addr;
+
+	void				*host_cmds_ptr;
+	dma_addr_t			host_cmds_addr;
+	int				ci;
+
+	void				*host_sg_tbl_ptr;
+	dma_addr_t			host_sg_tbl_addr;
+	int				sgi;
+
+	u32				bier;
+	char				trans_result;
+
+	unsigned int			card_inserted;
+	unsigned int			card_removed;
+	unsigned int			card_exist;
+
+	struct delayed_work		carddet_work;
+	struct delayed_work		idle_work;
+
+	spinlock_t			lock;
+	struct mutex			pcr_mutex;
+	struct completion		*done;
+	struct completion		*finish_me;
+
+	unsigned int			cur_clock;
+	bool				remove_pci;
+	bool				msi_en;
+
+#define EXTRA_CAPS_SD_SDR50		(1 << 0)
+#define EXTRA_CAPS_SD_SDR104		(1 << 1)
+#define EXTRA_CAPS_SD_DDR50		(1 << 2)
+#define EXTRA_CAPS_MMC_HSDDR		(1 << 3)
+#define EXTRA_CAPS_MMC_HS200		(1 << 4)
+#define EXTRA_CAPS_MMC_8BIT		(1 << 5)
+	u32				extra_caps;
+
+#define IC_VER_A			0
+#define IC_VER_B			1
+#define IC_VER_C			2
+#define IC_VER_D			3
+	u8				ic_version;
+
+	u8				sd30_drive_sel_1v8;
+	u8				sd30_drive_sel_3v3;
+	u8				card_drive_sel;
+#define ASPM_L1_EN			0x02
+	u8				aspm_en;
+	bool				aspm_enabled;
+
+#define PCR_MS_PMOS			(1 << 0)
+#define PCR_REVERSE_SOCKET		(1 << 1)
+	u32				flags;
+
+	u32				tx_initial_phase;
+	u32				rx_initial_phase;
+
+	const u32			*sd_pull_ctl_enable_tbl;
+	const u32			*sd_pull_ctl_disable_tbl;
+	const u32			*ms_pull_ctl_enable_tbl;
+	const u32			*ms_pull_ctl_disable_tbl;
+
+	const struct pcr_ops		*ops;
+	enum PDEV_STAT			state;
+
+	u16				reg_pm_ctrl3;
+
+	int				num_slots;
+	struct rtsx_slot		*slots;
+
+	u8				dma_error_count;
+};
+
+#define PID_524A	0x524A
+#define PID_5249		0x5249
+#define PID_5250		0x5250
+#define PID_525A	0x525A
+
+#define CHK_PCI_PID(pcr, pid)		((pcr)->pci->device == (pid))
+#define PCI_VID(pcr)			((pcr)->pci->vendor)
+#define PCI_PID(pcr)			((pcr)->pci->device)
+#define is_version(pcr, pid, ver)				\
+	(CHK_PCI_PID(pcr, pid) && (pcr)->ic_version == (ver))
+#define pcr_dbg(pcr, fmt, arg...)				\
+	dev_dbg(&(pcr)->pci->dev, fmt, ##arg)
+
+#define SDR104_PHASE(val)		((val) & 0xFF)
+#define SDR50_PHASE(val)		(((val) >> 8) & 0xFF)
+#define DDR50_PHASE(val)		(((val) >> 16) & 0xFF)
+#define SDR104_TX_PHASE(pcr)		SDR104_PHASE((pcr)->tx_initial_phase)
+#define SDR50_TX_PHASE(pcr)		SDR50_PHASE((pcr)->tx_initial_phase)
+#define DDR50_TX_PHASE(pcr)		DDR50_PHASE((pcr)->tx_initial_phase)
+#define SDR104_RX_PHASE(pcr)		SDR104_PHASE((pcr)->rx_initial_phase)
+#define SDR50_RX_PHASE(pcr)		SDR50_PHASE((pcr)->rx_initial_phase)
+#define DDR50_RX_PHASE(pcr)		DDR50_PHASE((pcr)->rx_initial_phase)
+#define SET_CLOCK_PHASE(sdr104, sdr50, ddr50)	\
+				(((ddr50) << 16) | ((sdr50) << 8) | (sdr104))
+
+void rtsx_pci_start_run(struct rtsx_pcr *pcr);
+int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data);
+int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data);
+int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
+int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
+void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr);
+void rtsx_pci_add_cmd(struct rtsx_pcr *pcr,
+		u8 cmd_type, u16 reg_addr, u8 mask, u8 data);
+void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
+int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
+int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int num_sg, bool read, int timeout);
+int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int num_sg, bool read);
+void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int num_sg, bool read);
+int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+		int count, bool read, int timeout);
+int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
+int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
+int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
+int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card);
+int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
+		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
+int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card);
+int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card);
+int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card);
+int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage);
+unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr);
+void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr);
+
+static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr)
+{
+	return (u8 *)(pcr->host_cmds_ptr);
+}
+
+static inline int rtsx_pci_update_cfg_byte(struct rtsx_pcr *pcr, int addr,
+		u8 mask, u8 append)
+{
+	int err;
+	u8 val;
+
+	err = pci_read_config_byte(pcr->pci, addr, &val);
+	if (err < 0)
+		return err;
+	return pci_write_config_byte(pcr->pci, addr, (val & mask) | append);
+}
+
+static inline void rtsx_pci_write_be32(struct rtsx_pcr *pcr, u16 reg, u32 val)
+{
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg,     0xFF, val >> 24);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, val >> 16);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, val >> 8);
+	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, val);
+}
+
+static inline int rtsx_pci_update_phy(struct rtsx_pcr *pcr, u8 addr,
+	u16 mask, u16 append)
+{
+	int err;
+	u16 val;
+
+	err = rtsx_pci_read_phy_register(pcr, addr, &val);
+	if (err < 0)
+		return err;
+
+	return rtsx_pci_write_phy_register(pcr, addr, (val & mask) | append);
+}
+
+#endif
diff --git a/include/linux/rtsx_usb.h b/include/linux/rtsx_usb.h
new file mode 100644
index 0000000..c446e4f
--- /dev/null
+++ b/include/linux/rtsx_usb.h
@@ -0,0 +1,628 @@ 
+/* Driver for Realtek RTS5139 USB card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Roger Tseng <rogerable@realtek.com>
+ */
+
+#ifndef __RTSX_USB_H
+#define __RTSX_USB_H
+
+#include <linux/usb.h>
+
+/* related module names */
+#define RTSX_USB_SD_CARD	0
+#define RTSX_USB_MS_CARD	1
+
+/* endpoint numbers */
+#define EP_BULK_OUT		1
+#define EP_BULK_IN		2
+#define EP_INTR_IN		3
+
+/* USB vendor requests */
+#define RTSX_USB_REQ_REG_OP	0x00
+#define RTSX_USB_REQ_POLL	0x02
+
+/* miscellaneous parameters */
+#define MIN_DIV_N		60
+#define MAX_DIV_N		120
+
+#define MAX_PHASE		15
+#define RX_TUNING_CNT		3
+
+#define QFN24			0
+#define LQFP48			1
+#define CHECK_PKG(ucr, pkg)	((ucr)->package == (pkg))
+
+/* data structures */
+struct rtsx_ucr {
+	u16			vendor_id;
+	u16			product_id;
+
+	int			package;
+	u8			ic_version;
+	bool			is_rts5179;
+
+	unsigned int		cur_clk;
+
+	u8			*cmd_buf;
+	unsigned int		cmd_idx;
+	u8			*rsp_buf;
+
+	struct usb_device	*pusb_dev;
+	struct usb_interface	*pusb_intf;
+	struct usb_sg_request	current_sg;
+	unsigned char		*iobuf;
+	dma_addr_t		iobuf_dma;
+
+	struct timer_list	sg_timer;
+	struct mutex		dev_mutex;
+};
+
+/* buffer size */
+#define IOBUF_SIZE		1024
+
+/* prototypes of exported functions */
+extern int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status);
+
+extern int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data);
+extern int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask,
+		u8 data);
+
+extern int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask,
+		u8 data);
+extern int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr,
+		u8 *data);
+
+extern void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type,
+		u16 reg_addr, u8 mask, u8 data);
+extern int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout);
+extern int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout);
+extern int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
+			      void *buf, unsigned int len, int use_sg,
+			      unsigned int *act_len, int timeout);
+
+extern int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len);
+extern int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len);
+extern int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock,
+		u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
+extern int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card);
+
+/* card status */
+#define SD_CD		0x01
+#define MS_CD		0x02
+#define XD_CD		0x04
+#define CD_MASK		(SD_CD | MS_CD | XD_CD)
+#define SD_WP		0x08
+
+/* reader command field offset & parameters */
+#define READ_REG_CMD		0
+#define WRITE_REG_CMD		1
+#define CHECK_REG_CMD		2
+
+#define PACKET_TYPE		4
+#define CNT_H			5
+#define CNT_L			6
+#define STAGE_FLAG		7
+#define CMD_OFFSET		8
+#define SEQ_WRITE_DATA_OFFSET	12
+
+#define BATCH_CMD		0
+#define SEQ_READ		1
+#define SEQ_WRITE		2
+
+#define STAGE_R			0x01
+#define STAGE_DI		0x02
+#define STAGE_DO		0x04
+#define STAGE_MS_STATUS		0x08
+#define STAGE_XD_STATUS		0x10
+#define MODE_C			0x00
+#define MODE_CR			(STAGE_R)
+#define MODE_CDIR		(STAGE_R | STAGE_DI)
+#define MODE_CDOR		(STAGE_R | STAGE_DO)
+
+#define EP0_OP_SHIFT		14
+#define EP0_READ_REG_CMD	2
+#define EP0_WRITE_REG_CMD	3
+
+#define rtsx_usb_cmd_hdr_tag(ucr)		\
+	do {					\
+		ucr->cmd_buf[0] = 'R';		\
+		ucr->cmd_buf[1] = 'T';		\
+		ucr->cmd_buf[2] = 'C';		\
+		ucr->cmd_buf[3] = 'R';		\
+	} while (0)
+
+static inline void rtsx_usb_init_cmd(struct rtsx_ucr *ucr)
+{
+	rtsx_usb_cmd_hdr_tag(ucr);
+	ucr->cmd_idx = 0;
+	ucr->cmd_buf[PACKET_TYPE] = BATCH_CMD;
+}
+
+/* internal register address */
+#define FPDCTL				0xFC00
+#define SSC_DIV_N_0			0xFC07
+#define SSC_CTL1			0xFC09
+#define SSC_CTL2			0xFC0A
+#define CFG_MODE			0xFC0E
+#define CFG_MODE_1			0xFC0F
+#define RCCTL				0xFC14
+#define SOF_WDOG			0xFC28
+#define SYS_DUMMY0			0xFC30
+
+#define MS_BLKEND			0xFD30
+#define MS_READ_START			0xFD31
+#define MS_READ_COUNT			0xFD32
+#define MS_WRITE_START			0xFD33
+#define MS_WRITE_COUNT			0xFD34
+#define MS_COMMAND			0xFD35
+#define MS_OLD_BLOCK_0			0xFD36
+#define MS_OLD_BLOCK_1			0xFD37
+#define MS_NEW_BLOCK_0			0xFD38
+#define MS_NEW_BLOCK_1			0xFD39
+#define MS_LOG_BLOCK_0			0xFD3A
+#define MS_LOG_BLOCK_1			0xFD3B
+#define MS_BUS_WIDTH			0xFD3C
+#define MS_PAGE_START			0xFD3D
+#define MS_PAGE_LENGTH			0xFD3E
+#define MS_CFG				0xFD40
+#define MS_TPC				0xFD41
+#define MS_TRANS_CFG			0xFD42
+#define MS_TRANSFER			0xFD43
+#define MS_INT_REG			0xFD44
+#define MS_BYTE_CNT			0xFD45
+#define MS_SECTOR_CNT_L			0xFD46
+#define MS_SECTOR_CNT_H			0xFD47
+#define MS_DBUS_H			0xFD48
+
+#define CARD_DMA1_CTL			0xFD5C
+#define CARD_PULL_CTL1			0xFD60
+#define CARD_PULL_CTL2			0xFD61
+#define CARD_PULL_CTL3			0xFD62
+#define CARD_PULL_CTL4			0xFD63
+#define CARD_PULL_CTL5			0xFD64
+#define CARD_PULL_CTL6			0xFD65
+#define CARD_EXIST			0xFD6F
+#define CARD_INT_PEND			0xFD71
+
+#define LDO_POWER_CFG			0xFD7B
+
+#define SD_CFG1				0xFDA0
+#define SD_CFG2				0xFDA1
+#define SD_CFG3				0xFDA2
+#define SD_STAT1			0xFDA3
+#define SD_STAT2			0xFDA4
+#define SD_BUS_STAT			0xFDA5
+#define SD_PAD_CTL			0xFDA6
+#define SD_SAMPLE_POINT_CTL		0xFDA7
+#define SD_PUSH_POINT_CTL		0xFDA8
+#define SD_CMD0				0xFDA9
+#define SD_CMD1				0xFDAA
+#define SD_CMD2				0xFDAB
+#define SD_CMD3				0xFDAC
+#define SD_CMD4				0xFDAD
+#define SD_CMD5				0xFDAE
+#define SD_BYTE_CNT_L			0xFDAF
+#define SD_BYTE_CNT_H			0xFDB0
+#define SD_BLOCK_CNT_L			0xFDB1
+#define SD_BLOCK_CNT_H			0xFDB2
+#define SD_TRANSFER			0xFDB3
+#define SD_CMD_STATE			0xFDB5
+#define SD_DATA_STATE			0xFDB6
+#define SD_VPCLK0_CTL			0xFC2A
+#define SD_VPCLK1_CTL			0xFC2B
+#define SD_DCMPS0_CTL			0xFC2C
+#define SD_DCMPS1_CTL			0xFC2D
+
+#define CARD_DMA1_CTL			0xFD5C
+
+#define HW_VERSION			0xFC01
+
+#define SSC_CLK_FPGA_SEL		0xFC02
+#define CLK_DIV				0xFC03
+#define SFSM_ED				0xFC04
+
+#define CD_DEGLITCH_WIDTH		0xFC20
+#define CD_DEGLITCH_EN			0xFC21
+#define AUTO_DELINK_EN			0xFC23
+
+#define FPGA_PULL_CTL			0xFC1D
+#define CARD_CLK_SOURCE			0xFC2E
+
+#define CARD_SHARE_MODE			0xFD51
+#define CARD_DRIVE_SEL			0xFD52
+#define CARD_STOP			0xFD53
+#define CARD_OE				0xFD54
+#define CARD_AUTO_BLINK			0xFD55
+#define CARD_GPIO			0xFD56
+#define SD30_DRIVE_SEL			0xFD57
+
+#define CARD_DATA_SOURCE		0xFD5D
+#define CARD_SELECT			0xFD5E
+
+#define CARD_CLK_EN			0xFD79
+#define CARD_PWR_CTL			0xFD7A
+
+#define OCPCTL				0xFD80
+#define OCPPARA1			0xFD81
+#define OCPPARA2			0xFD82
+#define OCPSTAT				0xFD83
+
+#define HS_USB_STAT			0xFE01
+#define HS_VCONTROL			0xFE26
+#define HS_VSTAIN			0xFE27
+#define HS_VLOADM			0xFE28
+#define HS_VSTAOUT			0xFE29
+
+#define MC_IRQ				0xFF00
+#define MC_IRQEN			0xFF01
+#define MC_FIFO_CTL			0xFF02
+#define MC_FIFO_BC0			0xFF03
+#define MC_FIFO_BC1			0xFF04
+#define MC_FIFO_STAT			0xFF05
+#define MC_FIFO_MODE			0xFF06
+#define MC_FIFO_RD_PTR0			0xFF07
+#define MC_FIFO_RD_PTR1			0xFF08
+#define MC_DMA_CTL			0xFF10
+#define MC_DMA_TC0			0xFF11
+#define MC_DMA_TC1			0xFF12
+#define MC_DMA_TC2			0xFF13
+#define MC_DMA_TC3			0xFF14
+#define MC_DMA_RST			0xFF15
+
+#define RBUF_SIZE_MASK			0xFBFF
+#define RBUF_BASE			0xF000
+#define PPBUF_BASE1			0xF800
+#define PPBUF_BASE2			0xFA00
+
+/* internal register value macros */
+#define POWER_OFF			0x03
+#define PARTIAL_POWER_ON		0x02
+#define POWER_ON			0x00
+#define POWER_MASK			0x03
+#define LDO3318_PWR_MASK		0x0C
+#define LDO_ON				0x00
+#define LDO_SUSPEND			0x08
+#define LDO_OFF				0x0C
+#define DV3318_AUTO_PWR_OFF		0x10
+#define FORCE_LDO_POWERB		0x60
+
+/* LDO_POWER_CFG */
+#define TUNE_SD18_MASK			0x1C
+#define TUNE_SD18_1V7			0x00
+#define TUNE_SD18_1V8			(0x01 << 2)
+#define TUNE_SD18_1V9			(0x02 << 2)
+#define TUNE_SD18_2V0			(0x03 << 2)
+#define TUNE_SD18_2V7			(0x04 << 2)
+#define TUNE_SD18_2V8			(0x05 << 2)
+#define TUNE_SD18_2V9			(0x06 << 2)
+#define TUNE_SD18_3V3			(0x07 << 2)
+
+/* CLK_DIV */
+#define CLK_CHANGE			0x80
+#define CLK_DIV_1			0x00
+#define CLK_DIV_2			0x01
+#define CLK_DIV_4			0x02
+#define CLK_DIV_8			0x03
+
+#define SSC_POWER_MASK			0x01
+#define SSC_POWER_DOWN			0x01
+#define SSC_POWER_ON			0x00
+
+#define FPGA_VER			0x80
+#define HW_VER_MASK			0x0F
+
+#define EXTEND_DMA1_ASYNC_SIGNAL	0x02
+
+/* CFG_MODE*/
+#define XTAL_FREE			0x80
+#define CLK_MODE_MASK			0x03
+#define CLK_MODE_12M_XTAL		0x00
+#define CLK_MODE_NON_XTAL		0x01
+#define CLK_MODE_24M_OSC		0x02
+#define CLK_MODE_48M_OSC		0x03
+
+/* CFG_MODE_1*/
+#define RTS5179				0x02
+
+#define NYET_EN				0x01
+#define NYET_MSAK			0x01
+
+#define SD30_DRIVE_MASK			0x07
+#define SD20_DRIVE_MASK			0x03
+
+#define DISABLE_SD_CD			0x08
+#define DISABLE_MS_CD			0x10
+#define DISABLE_XD_CD			0x20
+#define SD_CD_DEGLITCH_EN		0x01
+#define MS_CD_DEGLITCH_EN		0x02
+#define XD_CD_DEGLITCH_EN		0x04
+
+#define	CARD_SHARE_LQFP48		0x04
+#define	CARD_SHARE_QFN24		0x00
+#define CARD_SHARE_LQFP_SEL		0x04
+#define	CARD_SHARE_XD			0x00
+#define	CARD_SHARE_SD			0x01
+#define	CARD_SHARE_MS			0x02
+#define CARD_SHARE_MASK			0x03
+
+
+/* SD30_DRIVE_SEL */
+#define DRIVER_TYPE_A			0x05
+#define DRIVER_TYPE_B			0x03
+#define DRIVER_TYPE_C			0x02
+#define DRIVER_TYPE_D			0x01
+
+/* SD_BUS_STAT */
+#define	SD_CLK_TOGGLE_EN		0x80
+#define	SD_CLK_FORCE_STOP	        0x40
+#define	SD_DAT3_STATUS		        0x10
+#define	SD_DAT2_STATUS		        0x08
+#define	SD_DAT1_STATUS		        0x04
+#define	SD_DAT0_STATUS		        0x02
+#define	SD_CMD_STATUS			0x01
+
+/* SD_PAD_CTL */
+#define	SD_IO_USING_1V8		        0x80
+#define	SD_IO_USING_3V3		        0x7F
+#define	TYPE_A_DRIVING		        0x00
+#define	TYPE_B_DRIVING			0x01
+#define	TYPE_C_DRIVING			0x02
+#define	TYPE_D_DRIVING		        0x03
+
+/* CARD_CLK_EN */
+#define SD_CLK_EN			0x04
+#define MS_CLK_EN			0x08
+
+/* CARD_SELECT */
+#define SD_MOD_SEL			2
+#define MS_MOD_SEL			3
+
+/* CARD_SHARE_MODE */
+#define	CARD_SHARE_LQFP48		0x04
+#define	CARD_SHARE_QFN24		0x00
+#define CARD_SHARE_LQFP_SEL		0x04
+#define	CARD_SHARE_XD			0x00
+#define	CARD_SHARE_SD			0x01
+#define	CARD_SHARE_MS			0x02
+#define CARD_SHARE_MASK			0x03
+
+/* SSC_CTL1 */
+#define SSC_RSTB			0x80
+#define SSC_8X_EN			0x40
+#define SSC_FIX_FRAC			0x20
+#define SSC_SEL_1M			0x00
+#define SSC_SEL_2M			0x08
+#define SSC_SEL_4M			0x10
+#define SSC_SEL_8M			0x18
+
+/* SSC_CTL2 */
+#define SSC_DEPTH_MASK			0x03
+#define SSC_DEPTH_DISALBE		0x00
+#define SSC_DEPTH_2M			0x01
+#define SSC_DEPTH_1M			0x02
+#define SSC_DEPTH_512K			0x03
+
+/* SD_VPCLK0_CTL */
+#define PHASE_CHANGE			0x80
+#define PHASE_NOT_RESET			0x40
+
+/* SD_TRANSFER */
+#define	SD_TRANSFER_START		0x80
+#define	SD_TRANSFER_END			0x40
+#define SD_STAT_IDLE			0x20
+#define	SD_TRANSFER_ERR			0x10
+#define	SD_TM_NORMAL_WRITE		0x00
+#define	SD_TM_AUTO_WRITE_3		0x01
+#define	SD_TM_AUTO_WRITE_4		0x02
+#define	SD_TM_AUTO_READ_3		0x05
+#define	SD_TM_AUTO_READ_4		0x06
+#define	SD_TM_CMD_RSP			0x08
+#define	SD_TM_AUTO_WRITE_1		0x09
+#define	SD_TM_AUTO_WRITE_2		0x0A
+#define	SD_TM_NORMAL_READ		0x0C
+#define	SD_TM_AUTO_READ_1		0x0D
+#define	SD_TM_AUTO_READ_2		0x0E
+#define	SD_TM_AUTO_TUNING		0x0F
+
+/* SD_CFG1 */
+#define SD_CLK_DIVIDE_0			0x00
+#define	SD_CLK_DIVIDE_256		0xC0
+#define	SD_CLK_DIVIDE_128		0x80
+#define SD_CLK_DIVIDE_MASK		0xC0
+#define	SD_BUS_WIDTH_1BIT		0x00
+#define	SD_BUS_WIDTH_4BIT		0x01
+#define	SD_BUS_WIDTH_8BIT		0x02
+#define	SD_ASYNC_FIFO_RST		0x10
+#define	SD_20_MODE			0x00
+#define	SD_DDR_MODE			0x04
+#define	SD_30_MODE			0x08
+
+/* SD_CFG2 */
+#define	SD_CALCULATE_CRC7		0x00
+#define	SD_NO_CALCULATE_CRC7		0x80
+#define	SD_CHECK_CRC16			0x00
+#define	SD_NO_CHECK_CRC16		0x40
+#define SD_WAIT_CRC_TO_EN		0x20
+#define	SD_WAIT_BUSY_END		0x08
+#define	SD_NO_WAIT_BUSY_END		0x00
+#define	SD_CHECK_CRC7			0x00
+#define	SD_NO_CHECK_CRC7		0x04
+#define	SD_RSP_LEN_0			0x00
+#define	SD_RSP_LEN_6			0x01
+#define	SD_RSP_LEN_17			0x02
+#define	SD_RSP_TYPE_R0			0x04
+#define	SD_RSP_TYPE_R1			0x01
+#define	SD_RSP_TYPE_R1b			0x09
+#define	SD_RSP_TYPE_R2			0x02
+#define	SD_RSP_TYPE_R3			0x05
+#define	SD_RSP_TYPE_R4			0x05
+#define	SD_RSP_TYPE_R5			0x01
+#define	SD_RSP_TYPE_R6			0x01
+#define	SD_RSP_TYPE_R7			0x01
+
+/* SD_STAT1 */
+#define	SD_CRC7_ERR			0x80
+#define	SD_CRC16_ERR			0x40
+#define	SD_CRC_WRITE_ERR		0x20
+#define	SD_CRC_WRITE_ERR_MASK		0x1C
+#define	GET_CRC_TIME_OUT		0x02
+#define	SD_TUNING_COMPARE_ERR		0x01
+
+/* SD_DATA_STATE */
+#define SD_DATA_IDLE			0x80
+
+/* CARD_DATA_SOURCE */
+#define PINGPONG_BUFFER			0x01
+#define RING_BUFFER			0x00
+
+/* CARD_OE */
+#define SD_OUTPUT_EN			0x04
+#define MS_OUTPUT_EN			0x08
+
+/* CARD_STOP */
+#define SD_STOP				0x04
+#define MS_STOP				0x08
+#define SD_CLR_ERR			0x40
+#define MS_CLR_ERR			0x80
+
+/* CARD_CLK_SOURCE */
+#define CRC_FIX_CLK			(0x00 << 0)
+#define CRC_VAR_CLK0			(0x01 << 0)
+#define CRC_VAR_CLK1			(0x02 << 0)
+#define SD30_FIX_CLK			(0x00 << 2)
+#define SD30_VAR_CLK0			(0x01 << 2)
+#define SD30_VAR_CLK1			(0x02 << 2)
+#define SAMPLE_FIX_CLK			(0x00 << 4)
+#define SAMPLE_VAR_CLK0			(0x01 << 4)
+#define SAMPLE_VAR_CLK1			(0x02 << 4)
+
+/* SD_SAMPLE_POINT_CTL */
+#define	DDR_FIX_RX_DAT			0x00
+#define	DDR_VAR_RX_DAT			0x80
+#define	DDR_FIX_RX_DAT_EDGE		0x00
+#define	DDR_FIX_RX_DAT_14_DELAY		0x40
+#define	DDR_FIX_RX_CMD			0x00
+#define	DDR_VAR_RX_CMD			0x20
+#define	DDR_FIX_RX_CMD_POS_EDGE		0x00
+#define	DDR_FIX_RX_CMD_14_DELAY		0x10
+#define	SD20_RX_POS_EDGE		0x00
+#define	SD20_RX_14_DELAY		0x08
+#define SD20_RX_SEL_MASK		0x08
+
+/* SD_PUSH_POINT_CTL */
+#define	DDR_FIX_TX_CMD_DAT		0x00
+#define	DDR_VAR_TX_CMD_DAT		0x80
+#define	DDR_FIX_TX_DAT_14_TSU		0x00
+#define	DDR_FIX_TX_DAT_12_TSU		0x40
+#define	DDR_FIX_TX_CMD_NEG_EDGE		0x00
+#define	DDR_FIX_TX_CMD_14_AHEAD		0x20
+#define	SD20_TX_NEG_EDGE		0x00
+#define	SD20_TX_14_AHEAD		0x10
+#define SD20_TX_SEL_MASK		0x10
+#define	DDR_VAR_SDCLK_POL_SWAP		0x01
+
+/* MS_CFG */
+#define	SAMPLE_TIME_RISING		0x00
+#define	SAMPLE_TIME_FALLING		0x80
+#define	PUSH_TIME_DEFAULT		0x00
+#define	PUSH_TIME_ODD			0x40
+#define	NO_EXTEND_TOGGLE		0x00
+#define	EXTEND_TOGGLE_CHK		0x20
+#define	MS_BUS_WIDTH_1			0x00
+#define	MS_BUS_WIDTH_4			0x10
+#define	MS_BUS_WIDTH_8			0x18
+#define	MS_2K_SECTOR_MODE		0x04
+#define	MS_512_SECTOR_MODE		0x00
+#define	MS_TOGGLE_TIMEOUT_EN		0x00
+#define	MS_TOGGLE_TIMEOUT_DISEN		0x01
+#define MS_NO_CHECK_INT			0x02
+
+/* MS_TRANS_CFG */
+#define	WAIT_INT			0x80
+#define	NO_WAIT_INT			0x00
+#define	NO_AUTO_READ_INT_REG		0x00
+#define	AUTO_READ_INT_REG		0x40
+#define	MS_CRC16_ERR			0x20
+#define	MS_RDY_TIMEOUT			0x10
+#define	MS_INT_CMDNK			0x08
+#define	MS_INT_BREQ			0x04
+#define	MS_INT_ERR			0x02
+#define	MS_INT_CED			0x01
+
+/* MS_TRANSFER */
+#define	MS_TRANSFER_START		0x80
+#define	MS_TRANSFER_END			0x40
+#define	MS_TRANSFER_ERR			0x20
+#define	MS_BS_STATE			0x10
+#define	MS_TM_READ_BYTES		0x00
+#define	MS_TM_NORMAL_READ		0x01
+#define	MS_TM_WRITE_BYTES		0x04
+#define	MS_TM_NORMAL_WRITE		0x05
+#define	MS_TM_AUTO_READ			0x08
+#define	MS_TM_AUTO_WRITE		0x0C
+#define MS_TM_SET_CMD			0x06
+#define MS_TM_COPY_PAGE			0x07
+#define MS_TM_MULTI_READ		0x02
+#define MS_TM_MULTI_WRITE		0x03
+
+/* MC_FIFO_CTL */
+#define FIFO_FLUSH			0x01
+
+/* MC_DMA_RST */
+#define DMA_RESET  0x01
+
+/* MC_DMA_CTL */
+#define DMA_TC_EQ_0			0x80
+#define DMA_DIR_TO_CARD			0x00
+#define DMA_DIR_FROM_CARD		0x02
+#define DMA_EN				0x01
+#define DMA_128				(0 << 2)
+#define DMA_256				(1 << 2)
+#define DMA_512				(2 << 2)
+#define DMA_1024			(3 << 2)
+#define DMA_PACK_SIZE_MASK		0x0C
+
+/* CARD_INT_PEND */
+#define XD_INT				0x10
+#define MS_INT				0x08
+#define SD_INT				0x04
+
+/* LED operations*/
+static inline int rtsx_usb_turn_on_led(struct rtsx_ucr *ucr)
+{
+	return  rtsx_usb_ep0_write_register(ucr, CARD_GPIO, 0x03, 0x02);
+}
+
+static inline int rtsx_usb_turn_off_led(struct rtsx_ucr *ucr)
+{
+	return rtsx_usb_ep0_write_register(ucr, CARD_GPIO, 0x03, 0x03);
+}
+
+/* HW error clearing */
+static inline void rtsx_usb_clear_fsm_err(struct rtsx_ucr *ucr)
+{
+	rtsx_usb_ep0_write_register(ucr, SFSM_ED, 0xf8, 0xf8);
+}
+
+static inline void rtsx_usb_clear_dma_err(struct rtsx_ucr *ucr)
+{
+	rtsx_usb_ep0_write_register(ucr, MC_FIFO_CTL,
+			FIFO_FLUSH, FIFO_FLUSH);
+	rtsx_usb_ep0_write_register(ucr, MC_DMA_RST, DMA_RESET, DMA_RESET);
+}
+#endif /* __RTS51139_H */