From 5da4e04ae480aac5274dd020af3dfa21935028f7 Mon Sep 17 00:00:00 2001 From: Rui Feng Date: Wed, 29 Nov 2017 17:09:56 +0800 Subject: misc: rtsx: Add support for RTS5260 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 Reviewed-by: Daniel Bristot de Oliveira Tested-by: Perry Yuan Signed-off-by: Lee Jones --- drivers/misc/cardreader/rtsx_pcr.c | 123 ++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) (limited to 'drivers/misc/cardreader/rtsx_pcr.c') diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index b60bd2a3ba64..99adc67bbf73 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -62,6 +62,7 @@ static const struct pci_device_id rtsx_pci_ids[] = { { 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 @@ EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register); 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", -- cgit