From: Rui Feng <rui_f...@realsil.com.cn>

Add support for new chip rts5260.
In order to support rts5260, the definitions of
some internal registers and workflow have to be
modified and are different from its predecessors
and OCP function is added for RTS5260. So we need
this patch to ensure RTS5260 can work.

Signed-off-by: Rui Feng <rui_f...@realsil.com.cn>
Reviewed-by: Daniel Bristot de Oliveira <bris...@redhat.com>
Tested-by: Perry Yuan <perry_y...@dell.com>

v8 changes:
* add Tested-by
---
 drivers/misc/cardreader/Kconfig    |   2 +-
 drivers/misc/cardreader/Makefile   |   2 +-
 drivers/misc/cardreader/rts5260.c  | 748 +++++++++++++++++++++++++++++++++++++
 drivers/misc/cardreader/rts5260.h  |  45 +++
 drivers/misc/cardreader/rtsx_pcr.c | 123 +++++-
 drivers/misc/cardreader/rtsx_pcr.h |  10 +
 include/linux/rtsx_pci.h           | 234 +++++++++++-
 7 files changed, 1157 insertions(+), 7 deletions(-)
 create mode 100644 drivers/misc/cardreader/rts5260.c
 create mode 100644 drivers/misc/cardreader/rts5260.h

diff --git a/drivers/misc/cardreader/Kconfig b/drivers/misc/cardreader/Kconfig
index e7d835a..69e815e 100644
--- a/drivers/misc/cardreader/Kconfig
+++ b/drivers/misc/cardreader/Kconfig
@@ -4,7 +4,7 @@ config MISC_RTSX_PCI
        select MFD_CORE
        help
          This supports for Realtek PCI-Express card reader including rts5209,
-         rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411.
+         rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411, 
rts5260.
          Realtek card readers support access to many types of memory cards,
          such as Memory Stick, Memory Stick Pro, Secure Digital and
          MultiMediaCard.
diff --git a/drivers/misc/cardreader/Makefile b/drivers/misc/cardreader/Makefile
index 78337b2..9fabfcc 100644
--- a/drivers/misc/cardreader/Makefile
+++ b/drivers/misc/cardreader/Makefile
@@ -1,4 +1,4 @@
-rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
+rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o 
rts5260.o
 
 obj-$(CONFIG_MISC_RTSX_PCI)    += rtsx_pci.o
 obj-$(CONFIG_MISC_RTSX_USB)    += rtsx_usb.o
diff --git a/drivers/misc/cardreader/rts5260.c 
b/drivers/misc/cardreader/rts5260.c
new file mode 100644
index 0000000..3b30864
--- /dev/null
+++ b/drivers/misc/cardreader/rts5260.c
@@ -0,0 +1,748 @@
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2016-2017 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:
+ *   Steven FENG <steven_f...@realsil.com.cn>
+ *   Rui FENG <rui_f...@realsil.com.cn>
+ *   Wei WANG <wei_w...@realsil.com.cn>
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/rtsx_pci.h>
+
+#include "rts5260.h"
+#include "rtsx_pcr.h"
+
+static u8 rts5260_get_ic_version(struct rtsx_pcr *pcr)
+{
+       u8 val;
+
+       rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
+       return val & IC_VERSION_MASK;
+}
+
+static void rts5260_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
+{
+       u8 driving_3v3[6][3] = {
+               {0x94, 0x94, 0x94},
+               {0x11, 0x11, 0x18},
+               {0x55, 0x55, 0x5C},
+               {0x94, 0x94, 0x94},
+               {0x94, 0x94, 0x94},
+               {0xFF, 0xFF, 0xFF},
+       };
+       u8 driving_1v8[6][3] = {
+               {0x9A, 0x89, 0x89},
+               {0xC4, 0xC4, 0xC4},
+               {0x3C, 0x3C, 0x3C},
+               {0x9B, 0x99, 0x99},
+               {0x9A, 0x89, 0x89},
+               {0xFE, 0xFE, 0xFE},
+       };
+       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, MASK_8_BIT_DEF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+                               RELINK_TIME_MASK, 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, ALL_POWER_DOWN, ALL_POWER_DOWN);
+}
+
+static int rtsx_base_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, OLT_LED_CTL,
+               LED_SHINE_MASK, LED_SHINE_EN);
+}
+
+static int rtsx_base_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, OLT_LED_CTL,
+               LED_SHINE_MASK, LED_SHINE_DISABLE);
+}
+
+static int rts5260_turn_on_led(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, RTS5260_REG_GPIO_CTL0,
+               RTS5260_REG_GPIO_MASK, RTS5260_REG_GPIO_ON);
+}
+
+static int rts5260_turn_off_led(struct rtsx_pcr *pcr)
+{
+       return rtsx_pci_write_register(pcr, RTS5260_REG_GPIO_CTL0,
+               RTS5260_REG_GPIO_MASK, RTS5260_REG_GPIO_OFF);
+}
+
+/* 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 rts5260_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 rts5260_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 rts5260_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 rts5260_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,
+};
+
+static int sd_set_sample_push_timing_sd30(struct rtsx_pcr *pcr)
+{
+       rtsx_pci_write_register(pcr, SD_CFG1, SD_MODE_SELECT_MASK
+               | SD_ASYNC_FIFO_NOT_RST, SD_30_MODE | SD_ASYNC_FIFO_NOT_RST);
+       rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ);
+       rtsx_pci_write_register(pcr, CARD_CLK_SOURCE, 0xFF,
+                               CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
+       rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
+
+       return 0;
+}
+
+static int rts5260_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+       int err = 0;
+       struct rtsx_cr_option *option = &pcr->option;
+
+       if (option->ocp_en)
+               rtsx_pci_enable_ocp(pcr);
+
+       rtsx_pci_init_cmd(pcr);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CONFIG2,
+                        DV331812_VDD1, DV331812_VDD1);
+       err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
+       if (err < 0)
+               return err;
+
+       rtsx_pci_init_cmd(pcr);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_VCC_CFG0,
+                        RTS5260_DVCC_TUNE_MASK, RTS5260_DVCC_33);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_VCC_CFG1,
+                        LDO_POW_SDVDD1_MASK, LDO_POW_SDVDD1_ON);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CONFIG2,
+                        DV331812_POWERON, DV331812_POWERON);
+       err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
+
+       msleep(20);
+
+       if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50 ||
+           pcr->extra_caps & EXTRA_CAPS_SD_SDR104)
+               sd_set_sample_push_timing_sd30(pcr);
+
+       /* Initialize SD_CFG1 register */
+       rtsx_pci_write_register(pcr, SD_CFG1, 0xFF,
+                               SD_CLK_DIVIDE_128 | SD_20_MODE);
+
+       rtsx_pci_write_register(pcr, SD_SAMPLE_POINT_CTL,
+                               0xFF, SD20_RX_POS_EDGE);
+       rtsx_pci_write_register(pcr, SD_PUSH_POINT_CTL, 0xFF, 0);
+       rtsx_pci_write_register(pcr, CARD_STOP, SD_STOP | SD_CLR_ERR,
+                               SD_STOP | SD_CLR_ERR);
+
+       /* Reset SD_CFG3 register */
+       rtsx_pci_write_register(pcr, SD_CFG3, SD30_CLK_END_EN, 0);
+       rtsx_pci_write_register(pcr, REG_SD_STOP_SDCLK_CFG,
+                               SD30_CLK_STOP_CFG_EN | SD30_CLK_STOP_CFG1 |
+                               SD30_CLK_STOP_CFG0, 0);
+
+       rtsx_pci_write_register(pcr, REG_PRE_RW_MODE, EN_INFINITE_MODE, 0);
+
+       return err;
+}
+
+static int rts5260_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+       switch (voltage) {
+       case OUTPUT_3V3:
+               rtsx_pci_write_register(pcr, LDO_CONFIG2,
+                                       DV331812_VDD1, DV331812_VDD1);
+               rtsx_pci_write_register(pcr, LDO_DV18_CFG,
+                                       DV331812_MASK, DV331812_33);
+               rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8, 0);
+               break;
+       case OUTPUT_1V8:
+               rtsx_pci_write_register(pcr, LDO_CONFIG2,
+                                       DV331812_VDD1, DV331812_VDD1);
+               rtsx_pci_write_register(pcr, LDO_DV18_CFG,
+                                       DV331812_MASK, DV331812_17);
+               rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8,
+                                       SD_IO_USING_1V8);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set pad drive */
+       rtsx_pci_init_cmd(pcr);
+       rts5260_fill_driving(pcr, voltage);
+       return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
+}
+
+static void rts5260_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, RTS5260_DMA_RST_CTL_0,
+                               RTS5260_DMA_RST | RTS5260_ADMA3_RST,
+                               RTS5260_DMA_RST | RTS5260_ADMA3_RST);
+       rtsx_pci_write_register(pcr, RBCTL, RB_FLUSH, RB_FLUSH);
+}
+
+static void rts5260_card_before_power_off(struct rtsx_pcr *pcr)
+{
+       struct rtsx_cr_option *option = &pcr->option;
+
+       rts5260_stop_cmd(pcr);
+       rts5260_switch_output_voltage(pcr, OUTPUT_3V3);
+
+       if (option->ocp_en)
+               rtsx_pci_disable_ocp(pcr);
+}
+
+static int rts5260_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+       int err = 0;
+
+       rts5260_card_before_power_off(pcr);
+
+       rtsx_pci_init_cmd(pcr);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_VCC_CFG1,
+                        LDO_POW_SDVDD1_MASK, LDO_POW_SDVDD1_OFF);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CONFIG2,
+                        DV331812_POWERON, DV331812_POWEROFF);
+       err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
+
+       return err;
+}
+
+static void rts5260_init_ocp(struct rtsx_pcr *pcr)
+{
+       struct rtsx_cr_option *option = &pcr->option;
+
+       if (option->ocp_en) {
+               u8 mask, val;
+
+               rtsx_pci_write_register(pcr, RTS5260_DVCC_CTRL,
+                                       RTS5260_DVCC_OCP_EN |
+                                       RTS5260_DVCC_OCP_CL_EN,
+                                       RTS5260_DVCC_OCP_EN |
+                                       RTS5260_DVCC_OCP_CL_EN);
+               rtsx_pci_write_register(pcr, RTS5260_DVIO_CTRL,
+                                       RTS5260_DVIO_OCP_EN |
+                                       RTS5260_DVIO_OCP_CL_EN,
+                                       RTS5260_DVIO_OCP_EN |
+                                       RTS5260_DVIO_OCP_CL_EN);
+
+               rtsx_pci_write_register(pcr, RTS5260_DVCC_CTRL,
+                                       RTS5260_DVCC_OCP_THD_MASK,
+                                       option->sd_400mA_ocp_thd);
+
+               rtsx_pci_write_register(pcr, RTS5260_DVIO_CTRL,
+                                       RTS5260_DVIO_OCP_THD_MASK,
+                                       RTS5260_DVIO_OCP_THD_350);
+
+               rtsx_pci_write_register(pcr, RTS5260_DV331812_CFG,
+                                       RTS5260_DV331812_OCP_THD_MASK,
+                                       RTS5260_DV331812_OCP_THD_210);
+
+               mask = SD_OCP_GLITCH_MASK | SDVIO_OCP_GLITCH_MASK;
+               val = pcr->hw_param.ocp_glitch;
+               rtsx_pci_write_register(pcr, REG_OCPGLITCH, mask, val);
+
+               rtsx_pci_enable_ocp(pcr);
+       } else {
+               rtsx_pci_write_register(pcr, RTS5260_DVCC_CTRL,
+                                       RTS5260_DVCC_OCP_EN |
+                                       RTS5260_DVCC_OCP_CL_EN, 0);
+               rtsx_pci_write_register(pcr, RTS5260_DVIO_CTRL,
+                                       RTS5260_DVIO_OCP_EN |
+                                       RTS5260_DVIO_OCP_CL_EN, 0);
+       }
+}
+
+static void rts5260_enable_ocp(struct rtsx_pcr *pcr)
+{
+       u8 val = 0;
+
+       rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN, 0);
+
+       val = SD_OCP_INT_EN | SD_DETECT_EN;
+       val |= SDVIO_OCP_INT_EN | SDVIO_DETECT_EN;
+       rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
+       rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
+                               DV3318_DETECT_EN | DV3318_OCP_INT_EN,
+                               DV3318_DETECT_EN | DV3318_OCP_INT_EN);
+}
+
+static void rts5260_disable_ocp(struct rtsx_pcr *pcr)
+{
+       u8 mask = 0;
+
+       mask = SD_OCP_INT_EN | SD_DETECT_EN;
+       mask |= SDVIO_OCP_INT_EN | SDVIO_DETECT_EN;
+       rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
+       rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
+                               DV3318_DETECT_EN | DV3318_OCP_INT_EN, 0);
+
+       rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN,
+                               OC_POWER_DOWN);
+}
+
+int rts5260_get_ocpstat(struct rtsx_pcr *pcr, u8 *val)
+{
+       return rtsx_pci_read_register(pcr, REG_OCPSTAT, val);
+}
+
+int rts5260_get_ocpstat2(struct rtsx_pcr *pcr, u8 *val)
+{
+       return rtsx_pci_read_register(pcr, REG_DV3318_OCPSTAT, val);
+}
+
+void rts5260_clear_ocpstat(struct rtsx_pcr *pcr)
+{
+       u8 mask = 0;
+       u8 val = 0;
+
+       mask = SD_OCP_INT_CLR | SD_OC_CLR;
+       mask |= SDVIO_OCP_INT_CLR | SDVIO_OC_CLR;
+       val = SD_OCP_INT_CLR | SD_OC_CLR;
+       val |= SDVIO_OCP_INT_CLR | SDVIO_OC_CLR;
+
+       rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
+       rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
+                               DV3318_OCP_INT_CLR | DV3318_OCP_CLR,
+                               DV3318_OCP_INT_CLR | DV3318_OCP_CLR);
+       udelay(10);
+       rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
+       rtsx_pci_write_register(pcr, REG_DV3318_OCPCTL,
+                               DV3318_OCP_INT_CLR | DV3318_OCP_CLR, 0);
+}
+
+void rts5260_process_ocp(struct rtsx_pcr *pcr)
+{
+       if (!pcr->option.ocp_en)
+               return;
+
+       rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
+       rts5260_get_ocpstat2(pcr, &pcr->ocp_stat2);
+       if (pcr->card_exist & SD_EXIST)
+               sd_power_off_card3v3(pcr);
+       else if (pcr->card_exist & MS_EXIST)
+               ms_power_off_card3v3(pcr);
+
+       if (!(pcr->card_exist & MS_EXIST) && !(pcr->card_exist & SD_EXIST)) {
+               if ((pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER |
+                       SDVIO_OC_NOW | SDVIO_OC_EVER)) ||
+                       (pcr->ocp_stat2 & (DV3318_OCP_NOW | DV3318_OCP_EVER)))
+                       rtsx_pci_clear_ocpstat(pcr);
+               pcr->ocp_stat = 0;
+               pcr->ocp_stat2 = 0;
+       }
+
+       if ((pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER |
+                       SDVIO_OC_NOW | SDVIO_OC_EVER)) ||
+                       (pcr->ocp_stat2 & (DV3318_OCP_NOW | DV3318_OCP_EVER))) {
+               if (pcr->card_exist & SD_EXIST)
+                       rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
+               else if (pcr->card_exist & MS_EXIST)
+                       rtsx_pci_write_register(pcr, CARD_OE, MS_OUTPUT_EN, 0);
+       }
+}
+
+int rts5260_init_hw(struct rtsx_pcr *pcr)
+{
+       int err;
+
+       rtsx_pci_init_ocp(pcr);
+
+       rtsx_pci_init_cmd(pcr);
+
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, L1SUB_CONFIG1,
+                        AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
+       /* Rest L1SUB Config */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, L1SUB_CONFIG3, 0xFF, 0x00);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CLK_FORCE_CTL,
+                        CLK_PM_EN, CLK_PM_EN);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWD_SUSPEND_EN, 0xFF, 0xFF);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+                        PWR_GATE_EN, PWR_GATE_EN);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, REG_VREF,
+                        PWD_SUSPND_EN, PWD_SUSPND_EN);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RBCTL,
+                        U_AUTO_DMA_EN_MASK, U_AUTO_DMA_DISABLE);
+
+       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);
+
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG,
+                        OBFF_EN_MASK, OBFF_DISABLE);
+
+       err = rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static void rts5260_pwr_saving_setting(struct rtsx_pcr *pcr)
+{
+       int lss_l1_1, lss_l1_2;
+
+       lss_l1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN)
+                       | rtsx_check_dev_flag(pcr, PM_L1_1_EN);
+       lss_l1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN)
+                       | rtsx_check_dev_flag(pcr, PM_L1_2_EN);
+
+       if (lss_l1_2) {
+               pcr_dbg(pcr, "Set parameters for L1.2.");
+               rtsx_pci_write_register(pcr, PWR_GLOBAL_CTRL,
+                                       0xFF, PCIE_L1_2_EN);
+               rtsx_pci_write_register(pcr, PWR_FE_CTL,
+                                       0xFF, PCIE_L1_2_PD_FE_EN);
+       } else if (lss_l1_1) {
+               pcr_dbg(pcr, "Set parameters for L1.1.");
+               rtsx_pci_write_register(pcr, PWR_GLOBAL_CTRL,
+                                       0xFF, PCIE_L1_1_EN);
+               rtsx_pci_write_register(pcr, PWR_FE_CTL,
+                                       0xFF, PCIE_L1_1_PD_FE_EN);
+       } else {
+               pcr_dbg(pcr, "Set parameters for L1.");
+               rtsx_pci_write_register(pcr, PWR_GLOBAL_CTRL,
+                                       0xFF, PCIE_L1_0_EN);
+               rtsx_pci_write_register(pcr, PWR_FE_CTL,
+                                       0xFF, PCIE_L1_0_PD_FE_EN);
+       }
+
+       rtsx_pci_write_register(pcr, CFG_L1_0_PCIE_DPHY_RET_VALUE,
+                               0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
+       rtsx_pci_write_register(pcr, CFG_L1_0_PCIE_MAC_RET_VALUE,
+                               0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
+       rtsx_pci_write_register(pcr, CFG_L1_0_CRC_SD30_RET_VALUE,
+                               0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
+       rtsx_pci_write_register(pcr, CFG_L1_0_CRC_SD40_RET_VALUE,
+                               0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
+       rtsx_pci_write_register(pcr, CFG_L1_0_SYS_RET_VALUE,
+                               0xFF, CFG_L1_0_RET_VALUE_DEFAULT);
+       /*Option cut APHY*/
+       rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_0,
+                               0xFF, CFG_PCIE_APHY_OFF_0_DEFAULT);
+       rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_1,
+                               0xFF, CFG_PCIE_APHY_OFF_1_DEFAULT);
+       rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_2,
+                               0xFF, CFG_PCIE_APHY_OFF_2_DEFAULT);
+       rtsx_pci_write_register(pcr, CFG_PCIE_APHY_OFF_3,
+                               0xFF, CFG_PCIE_APHY_OFF_3_DEFAULT);
+       /*CDR DEC*/
+       rtsx_pci_write_register(pcr, PWC_CDR, 0xFF, PWC_CDR_DEFAULT);
+       /*PWMPFM*/
+       rtsx_pci_write_register(pcr, CFG_LP_FPWM_VALUE,
+                               0xFF, CFG_LP_FPWM_VALUE_DEFAULT);
+       /*No Power Saving WA*/
+       rtsx_pci_write_register(pcr, CFG_L1_0_CRC_MISC_RET_VALUE,
+                               0xFF, CFG_L1_0_CRC_MISC_RET_VALUE_DEFAULT);
+}
+
+static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
+{
+       struct rtsx_cr_option *option = &pcr->option;
+       u32 lval;
+
+       rtsx_pci_read_config_dword(pcr, PCR_ASPM_SETTING_5260, &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);
+
+       rts5260_pwr_saving_setting(pcr);
+
+       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;
+               }
+       }
+
+       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;
+}
+
+static int rts5260_extra_init_hw(struct rtsx_pcr *pcr)
+{
+       struct rtsx_cr_option *option = &pcr->option;
+
+       /* Set mcu_cnt to 7 to ensure data can be sampled properly */
+       rtsx_pci_write_register(pcr, 0xFC03, 0x7F, 0x07);
+       rtsx_pci_write_register(pcr, SSC_DIV_N_0, 0xFF, 0x5D);
+
+       rts5260_init_from_cfg(pcr);
+
+       /* force no MDIO*/
+       rtsx_pci_write_register(pcr, RTS5260_AUTOLOAD_CFG4,
+                               0xFF, RTS5260_MIMO_DISABLE);
+       /*Modify SDVCC Tune Default Parameters!*/
+       rtsx_pci_write_register(pcr, LDO_VCC_CFG0,
+                               RTS5260_DVCC_TUNE_MASK, RTS5260_DVCC_33);
+
+       rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL);
+
+       rts5260_init_hw(pcr);
+
+       /*
+        * 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 0;
+}
+
+void rts5260_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 void rts5260_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 rts5260_pcr_ops = {
+       .fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
+       .turn_on_led = rts5260_turn_on_led,
+       .turn_off_led = rts5260_turn_off_led,
+       .extra_init_hw = rts5260_extra_init_hw,
+       .enable_auto_blink = rtsx_base_enable_auto_blink,
+       .disable_auto_blink = rtsx_base_disable_auto_blink,
+       .card_power_on = rts5260_card_power_on,
+       .card_power_off = rts5260_card_power_off,
+       .switch_output_voltage = rts5260_switch_output_voltage,
+       .force_power_down = rtsx_base_force_power_down,
+       .stop_cmd = rts5260_stop_cmd,
+       .set_aspm = rts5260_set_aspm,
+       .set_l1off_cfg_sub_d0 = rts5260_set_l1off_cfg_sub_d0,
+       .enable_ocp = rts5260_enable_ocp,
+       .disable_ocp = rts5260_disable_ocp,
+       .init_ocp = rts5260_init_ocp,
+       .process_ocp = rts5260_process_ocp,
+       .get_ocpstat = rts5260_get_ocpstat,
+       .clear_ocpstat = rts5260_clear_ocpstat,
+};
+
+void rts5260_init_params(struct rtsx_pcr *pcr)
+{
+       struct rtsx_cr_option *option = &pcr->option;
+       struct rtsx_hw_param *hw_param = &pcr->hw_param;
+
+       pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+       pcr->num_slots = 2;
+
+       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 = rts5260_get_ic_version(pcr);
+       pcr->sd_pull_ctl_enable_tbl = rts5260_sd_pull_ctl_enable_tbl;
+       pcr->sd_pull_ctl_disable_tbl = rts5260_sd_pull_ctl_disable_tbl;
+       pcr->ms_pull_ctl_enable_tbl = rts5260_ms_pull_ctl_enable_tbl;
+       pcr->ms_pull_ctl_disable_tbl = rts5260_ms_pull_ctl_disable_tbl;
+
+       pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
+
+       pcr->ops = &rts5260_pcr_ops;
+
+       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_5250_DEF;
+       option->ltr_l1off_snooze_sspwrgate =
+               LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
+
+       option->ocp_en = 1;
+       if (option->ocp_en)
+               hw_param->interrupt_en |= SD_OC_INT_EN;
+       hw_param->ocp_glitch = SD_OCP_GLITCH_10M | SDVIO_OCP_GLITCH_800U;
+       option->sd_400mA_ocp_thd = RTS5260_DVCC_OCP_THD_550;
+       option->sd_800mA_ocp_thd = RTS5260_DVCC_OCP_THD_970;
+}
diff --git a/drivers/misc/cardreader/rts5260.h 
b/drivers/misc/cardreader/rts5260.h
new file mode 100644
index 0000000..53a1411
--- /dev/null
+++ b/drivers/misc/cardreader/rts5260.h
@@ -0,0 +1,45 @@
+#ifndef __RTS5260_H__
+#define __RTS5260_H__
+
+#define RTS5260_DVCC_CTRL              0xFF73
+#define RTS5260_DVCC_OCP_EN            (0x01 << 7)
+#define RTS5260_DVCC_OCP_THD_MASK      (0x07 << 4)
+#define RTS5260_DVCC_POWERON           (0x01 << 3)
+#define RTS5260_DVCC_OCP_CL_EN         (0x01 << 2)
+
+#define RTS5260_DVIO_CTRL              0xFF75
+#define RTS5260_DVIO_OCP_EN            (0x01 << 7)
+#define RTS5260_DVIO_OCP_THD_MASK      (0x07 << 4)
+#define RTS5260_DVIO_POWERON           (0x01 << 3)
+#define RTS5260_DVIO_OCP_CL_EN         (0x01 << 2)
+
+#define RTS5260_DV331812_CFG           0xFF71
+#define RTS5260_DV331812_OCP_EN                (0x01 << 7)
+#define RTS5260_DV331812_OCP_THD_MASK  (0x07 << 4)
+#define RTS5260_DV331812_POWERON       (0x01 << 3)
+#define RTS5260_DV331812_SEL           (0x01 << 2)
+#define RTS5260_DV331812_VDD1          (0x01 << 2)
+#define RTS5260_DV331812_VDD2          (0x00 << 2)
+
+#define RTS5260_DV331812_OCP_THD_120   (0x00 << 4)
+#define RTS5260_DV331812_OCP_THD_140   (0x01 << 4)
+#define RTS5260_DV331812_OCP_THD_160   (0x02 << 4)
+#define RTS5260_DV331812_OCP_THD_180   (0x03 << 4)
+#define RTS5260_DV331812_OCP_THD_210   (0x04 << 4)
+#define RTS5260_DV331812_OCP_THD_240   (0x05 << 4)
+#define RTS5260_DV331812_OCP_THD_270   (0x06 << 4)
+#define RTS5260_DV331812_OCP_THD_300   (0x07 << 4)
+
+#define RTS5260_DVIO_OCP_THD_250       (0x00 << 4)
+#define RTS5260_DVIO_OCP_THD_300       (0x01 << 4)
+#define RTS5260_DVIO_OCP_THD_350       (0x02 << 4)
+#define RTS5260_DVIO_OCP_THD_400       (0x03 << 4)
+#define RTS5260_DVIO_OCP_THD_450       (0x04 << 4)
+#define RTS5260_DVIO_OCP_THD_500       (0x05 << 4)
+#define RTS5260_DVIO_OCP_THD_550       (0x06 << 4)
+#define RTS5260_DVIO_OCP_THD_600       (0x07 << 4)
+
+#define RTS5260_DVCC_OCP_THD_550       (0x00 << 4)
+#define RTS5260_DVCC_OCP_THD_970       (0x05 << 4)
+
+#endif
diff --git a/drivers/misc/cardreader/rtsx_pcr.c 
b/drivers/misc/cardreader/rtsx_pcr.c
index b60bd2a..99adc67 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -62,6 +62,7 @@
        { 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 },
+       { PCI_DEVICE(0x10EC, 0x5260), PCI_CLASS_OTHERS << 16, 0xFF0000 },
        { 0, }
 };
 
@@ -334,6 +335,9 @@ int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 
addr, u16 *val)
 
 void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr)
 {
+       if (pcr->ops->stop_cmd)
+               return pcr->ops->stop_cmd(pcr);
+
        rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
        rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
 
@@ -826,7 +830,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned 
int card_clock,
                return err;
 
        /* Wait SSC clock stable */
-       udelay(10);
+       udelay(SSC_CLOCK_STABLE_WAIT);
        err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
        if (err < 0)
                return err;
@@ -963,6 +967,20 @@ static void rtsx_pci_card_detect(struct work_struct *work)
                                pcr->slots[RTSX_MS_CARD].p_dev);
 }
 
+void rtsx_pci_process_ocp(struct rtsx_pcr *pcr)
+{
+       if (pcr->ops->process_ocp)
+               pcr->ops->process_ocp(pcr);
+}
+
+int rtsx_pci_process_ocp_interrupt(struct rtsx_pcr *pcr)
+{
+       if (pcr->option.ocp_en)
+               rtsx_pci_process_ocp(pcr);
+
+       return 0;
+}
+
 static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
 {
        struct rtsx_pcr *pcr = dev_id;
@@ -987,6 +1005,9 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
 
        int_reg &= (pcr->bier | 0x7FFFFF);
 
+       if (int_reg & SD_OC_INT)
+               rtsx_pci_process_ocp_interrupt(pcr);
+
        if (int_reg & SD_INT) {
                if (int_reg & SD_EXIST) {
                        pcr->card_inserted |= SD_EXIST;
@@ -1119,6 +1140,102 @@ static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 
pm_state)
 }
 #endif
 
+void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
+{
+       u8 val = SD_OCP_INT_EN | SD_DETECT_EN;
+
+       if (pcr->ops->enable_ocp)
+               pcr->ops->enable_ocp(pcr);
+       else
+               rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
+
+}
+
+void rtsx_pci_disable_ocp(struct rtsx_pcr *pcr)
+{
+       u8 mask = SD_OCP_INT_EN | SD_DETECT_EN;
+
+       if (pcr->ops->disable_ocp)
+               pcr->ops->disable_ocp(pcr);
+       else
+               rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
+}
+
+void rtsx_pci_init_ocp(struct rtsx_pcr *pcr)
+{
+       if (pcr->ops->init_ocp) {
+               pcr->ops->init_ocp(pcr);
+       } else {
+               struct rtsx_cr_option *option = &(pcr->option);
+
+               if (option->ocp_en) {
+                       u8 val = option->sd_400mA_ocp_thd;
+
+                       rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN, 0);
+                       rtsx_pci_write_register(pcr, REG_OCPPARA1,
+                               SD_OCP_TIME_MASK, SD_OCP_TIME_800);
+                       rtsx_pci_write_register(pcr, REG_OCPPARA2,
+                               SD_OCP_THD_MASK, val);
+                       rtsx_pci_write_register(pcr, REG_OCPGLITCH,
+                               SD_OCP_GLITCH_MASK, pcr->hw_param.ocp_glitch);
+                       rtsx_pci_enable_ocp(pcr);
+               } else {
+                       /* OC power down */
+                       rtsx_pci_write_register(pcr, FPDCTL, OC_POWER_DOWN,
+                               OC_POWER_DOWN);
+               }
+       }
+}
+
+int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val)
+{
+       if (pcr->ops->get_ocpstat)
+               return pcr->ops->get_ocpstat(pcr, val);
+       else
+               return rtsx_pci_read_register(pcr, REG_OCPSTAT, val);
+}
+
+void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr)
+{
+       if (pcr->ops->clear_ocpstat) {
+               pcr->ops->clear_ocpstat(pcr);
+       } else {
+               u8 mask = SD_OCP_INT_CLR | SD_OC_CLR;
+               u8 val = SD_OCP_INT_CLR | SD_OC_CLR;
+
+               rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
+               rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
+       }
+}
+
+int sd_power_off_card3v3(struct rtsx_pcr *pcr)
+{
+       rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
+               MS_CLK_EN | SD40_CLK_EN, 0);
+       rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
+
+       rtsx_pci_card_power_off(pcr, RTSX_SD_CARD);
+
+       msleep(50);
+
+       rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD);
+
+       return 0;
+}
+
+int ms_power_off_card3v3(struct rtsx_pcr *pcr)
+{
+       rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
+               MS_CLK_EN | SD40_CLK_EN, 0);
+
+       rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD);
+
+       rtsx_pci_write_register(pcr, CARD_OE, MS_OUTPUT_EN, 0);
+       rtsx_pci_card_power_off(pcr, RTSX_MS_CARD);
+
+       return 0;
+}
+
 static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
 {
        int err;
@@ -1189,6 +1306,7 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
        case PID_5250:
        case PID_524A:
        case PID_525A:
+       case PID_5260:
                rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
                break;
        default:
@@ -1265,6 +1383,9 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
        case 0x5286:
                rtl8402_init_params(pcr);
                break;
+       case 0x5260:
+               rts5260_init_params(pcr);
+               break;
        }
 
        pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n",
diff --git a/drivers/misc/cardreader/rtsx_pcr.h 
b/drivers/misc/cardreader/rtsx_pcr.h
index b0691c9..c544e35 100644
--- a/drivers/misc/cardreader/rtsx_pcr.h
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -44,6 +44,8 @@
 #define ASPM_MASK_NEG          0xFC
 #define MASK_8_BIT_DEF         0xFF
 
+#define SSC_CLOCK_STABLE_WAIT  130
+
 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);
 
@@ -57,6 +59,7 @@
 void rts524a_init_params(struct rtsx_pcr *pcr);
 void rts525a_init_params(struct rtsx_pcr *pcr);
 void rtl8411b_init_params(struct rtsx_pcr *pcr);
+void rts5260_init_params(struct rtsx_pcr *pcr);
 
 static inline u8 map_sd_drive(int idx)
 {
@@ -99,5 +102,12 @@ static inline u8 map_sd_drive(int idx)
 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);
+void rtsx_pci_init_ocp(struct rtsx_pcr *pcr);
+void rtsx_pci_disable_ocp(struct rtsx_pcr *pcr);
+void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr);
+int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val);
+void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr);
+int sd_power_off_card3v3(struct rtsx_pcr *pcr);
+int ms_power_off_card3v3(struct rtsx_pcr *pcr);
 
 #endif
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 82abac7..a44670e 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -203,6 +203,7 @@
 #define   SD_DDR_MODE                  0x04
 #define   SD_30_MODE                   0x08
 #define   SD_CLK_DIVIDE_MASK           0xC0
+#define   SD_MODE_SELECT_MASK          0x0C
 #define SD_CFG2                                0xFDA1
 #define   SD_CALCULATE_CRC7            0x00
 #define   SD_NO_CALCULATE_CRC7         0x80
@@ -226,6 +227,7 @@
 #define   SD_RSP_TYPE_R6               0x01
 #define   SD_RSP_TYPE_R7               0x01
 #define SD_CFG3                                0xFDA2
+#define   SD30_CLK_END_EN              0x10
 #define   SD_RSP_80CLK_TIMEOUT_EN      0x01
 
 #define SD_STAT1                       0xFDA3
@@ -309,6 +311,12 @@
 
 #define SD_DATA_STATE                  0xFDB6
 #define   SD_DATA_IDLE                 0x80
+#define REG_SD_STOP_SDCLK_CFG          0xFDB8
+#define   SD30_CLK_STOP_CFG_EN         0x04
+#define   SD30_CLK_STOP_CFG1           0x02
+#define   SD30_CLK_STOP_CFG0           0x01
+#define REG_PRE_RW_MODE                        0xFD70
+#define EN_INFINITE_MODE               0x01
 
 #define SRCTL                          0xFC13
 
@@ -434,6 +442,7 @@
 #define CARD_CLK_EN                    0xFD69
 #define   SD_CLK_EN                    0x04
 #define   MS_CLK_EN                    0x08
+#define   SD40_CLK_EN          0x10
 #define SDIO_CTRL                      0xFD6B
 #define CD_PAD_CTL                     0xFD73
 #define   CD_DISABLE_MASK              0x07
@@ -453,8 +462,8 @@
 #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   ALL_POWER_DOWN               0x03
+#define   OC_POWER_DOWN                        0x02
 #define PDINFO                         0xFC01
 
 #define CLK_CTL                                0xFC02
@@ -490,6 +499,9 @@
 
 #define FPGA_PULL_CTL                  0xFC1D
 #define OLT_LED_CTL                    0xFC1E
+#define   LED_SHINE_MASK               0x08
+#define   LED_SHINE_EN                 0x08
+#define   LED_SHINE_DISABLE            0x00
 #define GPIO_CTL                       0xFC1F
 
 #define LDO_CTL                                0xFC1E
@@ -511,7 +523,11 @@
 #define   BPP_LDO_ON                   0x00
 #define   BPP_LDO_SUSPEND              0x02
 #define   BPP_LDO_OFF                  0x03
+#define EFUSE_CTL                      0xFC30
+#define EFUSE_ADD                      0xFC31
 #define SYS_VER                                0xFC32
+#define EFUSE_DATAL                    0xFC34
+#define EFUSE_DATAH                    0xFC35
 
 #define CARD_PULL_CTL1                 0xFD60
 #define CARD_PULL_CTL2                 0xFD61
@@ -553,6 +569,9 @@
 #define RBBC1                          0xFE2F
 #define RBDAT                          0xFE30
 #define RBCTL                          0xFE34
+#define   U_AUTO_DMA_EN_MASK           0x20
+#define   U_AUTO_DMA_DISABLE           0x00
+#define   RB_FLUSH                     0x80
 #define CFGADDR0                       0xFE35
 #define CFGADDR1                       0xFE36
 #define CFGDATA0                       0xFE37
@@ -581,6 +600,8 @@
 #define LTR_LATENCY_MODE_HW            0
 #define LTR_LATENCY_MODE_SW            BIT(6)
 #define OBFF_CFG                       0xFE4C
+#define   OBFF_EN_MASK                 0x03
+#define   OBFF_DISABLE                 0x00
 
 #define CDRESUMECTL                    0xFE52
 #define WAKE_SEL_CTL                   0xFE54
@@ -595,6 +616,7 @@
 #define   FORCE_ASPM_L0_EN             0x01
 #define   FORCE_ASPM_NO_ASPM           0x00
 #define PM_CLK_FORCE_CTL               0xFE58
+#define   CLK_PM_EN                    0x01
 #define FUNC_FORCE_CTL                 0xFE59
 #define   FUNC_FORCE_UPME_XMT_DBG      0x02
 #define PERST_GLITCH_WIDTH             0xFE5C
@@ -620,14 +642,23 @@
 #define LDO_PWR_SEL                    0xFE78
 
 #define L1SUB_CONFIG1                  0xFE8D
+#define   AUX_CLK_ACTIVE_SEL_MASK      0x01
+#define   MAC_CKSW_DONE                        0x00
 #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   IC_VERSION_MASK              0x0F
 
+#define REG_VREF                       0xFE97
+#define   PWD_SUSPND_EN                        0x10
+#define RTS5260_DMA_RST_CTL_0          0xFEBF
+#define   RTS5260_DMA_RST              0x80
+#define   RTS5260_ADMA3_RST            0x40
 #define AUTOLOAD_CFG_BASE              0xFF00
+#define RELINK_TIME_MASK               0x01
 #define PETXCFG                                0xFF03
 #define FORCE_CLKREQ_DELINK_MASK       BIT(7)
 #define FORCE_CLKREQ_LOW       0x80
@@ -667,15 +698,24 @@
 #define LDO_DV18_CFG                   0xFF70
 #define   LDO_DV18_SR_MASK             0xC0
 #define   LDO_DV18_SR_DF               0x40
+#define   DV331812_MASK                        0x70
+#define   DV331812_33                  0x70
+#define   DV331812_17                  0x30
 
 #define LDO_CONFIG2                    0xFF71
 #define   LDO_D3318_MASK               0x07
 #define   LDO_D3318_33V                        0x07
 #define   LDO_D3318_18V                        0x02
+#define   DV331812_VDD1                        0x04
+#define   DV331812_POWERON             0x08
+#define   DV331812_POWEROFF            0x00
 
 #define LDO_VCC_CFG0                   0xFF72
 #define   LDO_VCC_LMTVTH_MASK          0x30
 #define   LDO_VCC_LMTVTH_2A            0x10
+/*RTS5260*/
+#define   RTS5260_DVCC_TUNE_MASK       0x70
+#define   RTS5260_DVCC_33              0x70
 
 #define LDO_VCC_CFG1                   0xFF73
 #define   LDO_VCC_REF_TUNE_MASK                0x30
@@ -684,6 +724,10 @@
 #define   LDO_VCC_1V8                  0x04
 #define   LDO_VCC_3V3                  0x07
 #define   LDO_VCC_LMT_EN               0x08
+/*RTS5260*/
+#define          LDO_POW_SDVDD1_MASK           0x08
+#define          LDO_POW_SDVDD1_ON             0x08
+#define          LDO_POW_SDVDD1_OFF            0x00
 
 #define LDO_VIO_CFG                    0xFF75
 #define   LDO_VIO_SR_MASK              0xC0
@@ -711,6 +755,160 @@
 #define   SD_VIO_LDO_1V8               0x40
 #define   SD_VIO_LDO_3V3               0x70
 
+#define RTS5260_AUTOLOAD_CFG4          0xFF7F
+#define   RTS5260_MIMO_DISABLE         0x8A
+
+#define RTS5260_REG_GPIO_CTL0          0xFC1A
+#define   RTS5260_REG_GPIO_MASK                0x01
+#define   RTS5260_REG_GPIO_ON          0x01
+#define   RTS5260_REG_GPIO_OFF         0x00
+
+#define PWR_GLOBAL_CTRL                        0xF200
+#define PCIE_L1_2_EN                   0x0C
+#define PCIE_L1_1_EN                   0x0A
+#define PCIE_L1_0_EN                   0x09
+#define PWR_FE_CTL                     0xF201
+#define PCIE_L1_2_PD_FE_EN             0x0C
+#define PCIE_L1_1_PD_FE_EN             0x0A
+#define PCIE_L1_0_PD_FE_EN             0x09
+#define CFG_PCIE_APHY_OFF_0            0xF204
+#define CFG_PCIE_APHY_OFF_0_DEFAULT    0xBF
+#define CFG_PCIE_APHY_OFF_1            0xF205
+#define CFG_PCIE_APHY_OFF_1_DEFAULT    0xFF
+#define CFG_PCIE_APHY_OFF_2            0xF206
+#define CFG_PCIE_APHY_OFF_2_DEFAULT    0x01
+#define CFG_PCIE_APHY_OFF_3            0xF207
+#define CFG_PCIE_APHY_OFF_3_DEFAULT    0x00
+#define CFG_L1_0_PCIE_MAC_RET_VALUE    0xF20C
+#define CFG_L1_0_PCIE_DPHY_RET_VALUE   0xF20E
+#define CFG_L1_0_SYS_RET_VALUE         0xF210
+#define CFG_L1_0_CRC_MISC_RET_VALUE    0xF212
+#define CFG_L1_0_CRC_SD30_RET_VALUE    0xF214
+#define CFG_L1_0_CRC_SD40_RET_VALUE    0xF216
+#define CFG_LP_FPWM_VALUE              0xF219
+#define CFG_LP_FPWM_VALUE_DEFAULT      0x18
+#define PWC_CDR                                0xF253
+#define PWC_CDR_DEFAULT                        0x03
+#define CFG_L1_0_RET_VALUE_DEFAULT     0x1B
+#define CFG_L1_0_CRC_MISC_RET_VALUE_DEFAULT    0x0C
+
+/* OCPCTL */
+#define SD_DETECT_EN                   0x08
+#define SD_OCP_INT_EN                  0x04
+#define SD_OCP_INT_CLR                 0x02
+#define SD_OC_CLR                      0x01
+
+#define SDVIO_DETECT_EN                        (1 << 7)
+#define SDVIO_OCP_INT_EN               (1 << 6)
+#define SDVIO_OCP_INT_CLR              (1 << 5)
+#define SDVIO_OC_CLR                   (1 << 4)
+
+/* OCPSTAT */
+#define SD_OCP_DETECT                  0x08
+#define SD_OC_NOW                      0x04
+#define SD_OC_EVER                     0x02
+
+#define SDVIO_OC_NOW                   (1 << 6)
+#define SDVIO_OC_EVER                  (1 << 5)
+
+#define REG_OCPCTL                     0xFD6A
+#define REG_OCPSTAT                    0xFD6E
+#define REG_OCPGLITCH                  0xFD6C
+#define REG_OCPPARA1                   0xFD6B
+#define REG_OCPPARA2                   0xFD6D
+
+/* rts5260 DV3318 OCP-related registers */
+#define REG_DV3318_OCPCTL              0xFD89
+#define DV3318_OCP_TIME_MASK   0xF0
+#define DV3318_DETECT_EN               0x08
+#define DV3318_OCP_INT_EN              0x04
+#define DV3318_OCP_INT_CLR             0x02
+#define DV3318_OCP_CLR                 0x01
+
+#define REG_DV3318_OCPSTAT             0xFD8A
+#define DV3318_OCP_GlITCH_TIME_MASK    0xF0
+#define DV3318_OCP_DETECT              0x08
+#define DV3318_OCP_NOW                 0x04
+#define DV3318_OCP_EVER                        0x02
+
+#define SD_OCP_GLITCH_MASK             0x0F
+
+/* OCPPARA1 */
+#define SDVIO_OCP_TIME_60              0x00
+#define SDVIO_OCP_TIME_100             0x10
+#define SDVIO_OCP_TIME_200             0x20
+#define SDVIO_OCP_TIME_400             0x30
+#define SDVIO_OCP_TIME_600             0x40
+#define SDVIO_OCP_TIME_800             0x50
+#define SDVIO_OCP_TIME_1100            0x60
+#define SDVIO_OCP_TIME_MASK            0x70
+
+#define SD_OCP_TIME_60                 0x00
+#define SD_OCP_TIME_100                        0x01
+#define SD_OCP_TIME_200                        0x02
+#define SD_OCP_TIME_400                        0x03
+#define SD_OCP_TIME_600                        0x04
+#define SD_OCP_TIME_800                        0x05
+#define SD_OCP_TIME_1100               0x06
+#define SD_OCP_TIME_MASK               0x07
+
+/* OCPPARA2 */
+#define SDVIO_OCP_THD_190              0x00
+#define SDVIO_OCP_THD_250              0x10
+#define SDVIO_OCP_THD_320              0x20
+#define SDVIO_OCP_THD_380              0x30
+#define SDVIO_OCP_THD_440              0x40
+#define SDVIO_OCP_THD_500              0x50
+#define SDVIO_OCP_THD_570              0x60
+#define SDVIO_OCP_THD_630              0x70
+#define SDVIO_OCP_THD_MASK             0x70
+
+#define SD_OCP_THD_450                 0x00
+#define SD_OCP_THD_550                 0x01
+#define SD_OCP_THD_650                 0x02
+#define SD_OCP_THD_750                 0x03
+#define SD_OCP_THD_850                 0x04
+#define SD_OCP_THD_950                 0x05
+#define SD_OCP_THD_1050                        0x06
+#define SD_OCP_THD_1150                        0x07
+#define SD_OCP_THD_MASK                        0x07
+
+#define SDVIO_OCP_GLITCH_MASK          0xF0
+#define SDVIO_OCP_GLITCH_NONE          0x00
+#define SDVIO_OCP_GLITCH_50U           0x10
+#define SDVIO_OCP_GLITCH_100U          0x20
+#define SDVIO_OCP_GLITCH_200U          0x30
+#define SDVIO_OCP_GLITCH_600U          0x40
+#define SDVIO_OCP_GLITCH_800U          0x50
+#define SDVIO_OCP_GLITCH_1M            0x60
+#define SDVIO_OCP_GLITCH_2M            0x70
+#define SDVIO_OCP_GLITCH_3M            0x80
+#define SDVIO_OCP_GLITCH_4M            0x90
+#define SDVIO_OCP_GLIVCH_5M            0xA0
+#define SDVIO_OCP_GLITCH_6M            0xB0
+#define SDVIO_OCP_GLITCH_7M            0xC0
+#define SDVIO_OCP_GLITCH_8M            0xD0
+#define SDVIO_OCP_GLITCH_9M            0xE0
+#define SDVIO_OCP_GLITCH_10M           0xF0
+
+#define SD_OCP_GLITCH_MASK             0x0F
+#define SD_OCP_GLITCH_NONE             0x00
+#define SD_OCP_GLITCH_50U              0x01
+#define SD_OCP_GLITCH_100U             0x02
+#define SD_OCP_GLITCH_200U             0x03
+#define SD_OCP_GLITCH_600U             0x04
+#define SD_OCP_GLITCH_800U             0x05
+#define SD_OCP_GLITCH_1M               0x06
+#define SD_OCP_GLITCH_2M               0x07
+#define SD_OCP_GLITCH_3M               0x08
+#define SD_OCP_GLITCH_4M               0x09
+#define SD_OCP_GLIVCH_5M               0x0A
+#define SD_OCP_GLITCH_6M               0x0B
+#define SD_OCP_GLITCH_7M               0x0C
+#define SD_OCP_GLITCH_8M               0x0D
+#define SD_OCP_GLITCH_9M               0x0E
+#define SD_OCP_GLITCH_10M              0x0F
+
 /* Phy register */
 #define PHY_PCR                                0x00
 #define   PHY_PCR_FORCE_CODE           0xB000
@@ -857,6 +1055,7 @@
 
 #define PCR_ASPM_SETTING_REG1          0x160
 #define PCR_ASPM_SETTING_REG2          0x168
+#define PCR_ASPM_SETTING_5260          0x178
 
 #define PCR_SETTING_REG1               0x724
 #define PCR_SETTING_REG2               0x814
@@ -890,6 +1089,7 @@ struct pcr_ops {
        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            (*stop_cmd)(struct rtsx_pcr *pcr);
 
        void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
        int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency);
@@ -897,6 +1097,12 @@ struct pcr_ops {
        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);
+       void (*enable_ocp)(struct rtsx_pcr *pcr);
+       void (*disable_ocp)(struct rtsx_pcr *pcr);
+       void (*init_ocp)(struct rtsx_pcr *pcr);
+       void (*process_ocp)(struct rtsx_pcr *pcr);
+       int (*get_ocpstat)(struct rtsx_pcr *pcr, u8 *val);
+       void (*clear_ocpstat)(struct rtsx_pcr *pcr);
 };
 
 enum PDEV_STAT  {PDEV_STAT_IDLE, PDEV_STAT_RUN};
@@ -935,6 +1141,9 @@ enum dev_aspm_mode {
  * @l1_snooze_delay: l1 snooze delay
  * @ltr_l1off_sspwrgate: ltr l1off sspwrgate
  * @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate
+ * @ocp_en: enable ocp flag
+ * @sd_400mA_ocp_thd: 400mA ocp thd
+ * @sd_800mA_ocp_thd: 800mA ocp thd
  */
 struct rtsx_cr_option {
        u32 dev_flags;
@@ -949,6 +1158,19 @@ struct rtsx_cr_option {
        u32 l1_snooze_delay;
        u8 ltr_l1off_sspwrgate;
        u8 ltr_l1off_snooze_sspwrgate;
+       bool ocp_en;
+       u8 sd_400mA_ocp_thd;
+       u8 sd_800mA_ocp_thd;
+};
+
+/*
+ * struct rtsx_hw_param  - card reader hardware param
+ * @interrupt_en: indicate which interrutp enable
+ * @ocp_glitch: ocp glitch time
+ */
+struct rtsx_hw_param {
+       u32 interrupt_en;
+       u8 ocp_glitch;
 };
 
 #define rtsx_set_dev_flag(cr, flag) \
@@ -963,6 +1185,7 @@ struct rtsx_pcr {
        unsigned int                    id;
        int                             pcie_cap;
        struct rtsx_cr_option   option;
+       struct rtsx_hw_param hw_param;
 
        /* pci resources */
        unsigned long                   addr;
@@ -1042,12 +1265,15 @@ struct rtsx_pcr {
        struct rtsx_slot                *slots;
 
        u8                              dma_error_count;
+       u8                      ocp_stat;
+       u8                      ocp_stat2;
 };
 
 #define PID_524A       0x524A
-#define PID_5249               0x5249
-#define PID_5250               0x5250
+#define PID_5249       0x5249
+#define PID_5250       0x5250
 #define PID_525A       0x525A
+#define PID_5260       0x5260
 
 #define CHK_PCI_PID(pcr, pid)          ((pcr)->pci->device == (pid))
 #define PCI_VID(pcr)                   ((pcr)->pci->vendor)
-- 
1.9.1

Reply via email to