18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Driver for Realtek PCI-Express card reader 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: 78c2ecf20Sopenharmony_ci * Wei WANG <wei_wang@realsil.com.cn> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/rtsx_pci.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "rtsx_pcr.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic u8 rts5209_get_ic_version(struct rtsx_pcr *pcr) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci u8 val; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci val = rtsx_pci_readb(pcr, 0x1C); 218c2ecf20Sopenharmony_ci return val & 0x0F; 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct pci_dev *pdev = pcr->pci; 278c2ecf20Sopenharmony_ci u32 reg; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, PCR_SETTING_REG1, ®); 308c2ecf20Sopenharmony_ci pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (rts5209_vendor_setting1_valid(reg)) { 338c2ecf20Sopenharmony_ci if (rts5209_reg_check_ms_pmos(reg)) 348c2ecf20Sopenharmony_ci pcr->flags |= PCR_MS_PMOS; 358c2ecf20Sopenharmony_ci pcr->aspm_en = rts5209_reg_to_aspm(reg); 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, PCR_SETTING_REG2, ®); 398c2ecf20Sopenharmony_ci pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (rts5209_vendor_setting2_valid(reg)) { 428c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_1v8 = 438c2ecf20Sopenharmony_ci rts5209_reg_to_sd30_drive_sel_1v8(reg); 448c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_3v3 = 458c2ecf20Sopenharmony_ci rts5209_reg_to_sd30_drive_sel_3v3(reg); 468c2ecf20Sopenharmony_ci pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg); 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int rts5209_extra_init_hw(struct rtsx_pcr *pcr) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Turn off LED */ 608c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); 618c2ecf20Sopenharmony_ci /* Reset ASPM state to default value */ 628c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); 638c2ecf20Sopenharmony_ci /* Force CLKREQ# PIN to drive 0 to request clock */ 648c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); 658c2ecf20Sopenharmony_ci /* Configure GPIO as output */ 668c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); 678c2ecf20Sopenharmony_ci /* Configure driving */ 688c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, 698c2ecf20Sopenharmony_ci 0xFF, pcr->sd30_drive_sel_3v3); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return rtsx_pci_send_cmd(pcr, 100); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int rts5209_optimize_phy(struct rtsx_pcr *pcr) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int rts5209_turn_on_led(struct rtsx_pcr *pcr) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int rts5209_turn_off_led(struct rtsx_pcr *pcr) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int rts5209_enable_auto_blink(struct rtsx_pcr *pcr) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int rts5209_disable_auto_blink(struct rtsx_pcr *pcr) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int rts5209_card_power_on(struct rtsx_pcr *pcr, int card) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci int err; 1028c2ecf20Sopenharmony_ci u8 pwr_mask, partial_pwr_on, pwr_on; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci pwr_mask = SD_POWER_MASK; 1058c2ecf20Sopenharmony_ci partial_pwr_on = SD_PARTIAL_POWER_ON; 1068c2ecf20Sopenharmony_ci pwr_on = SD_POWER_ON; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { 1098c2ecf20Sopenharmony_ci pwr_mask = MS_POWER_MASK; 1108c2ecf20Sopenharmony_ci partial_pwr_on = MS_PARTIAL_POWER_ON; 1118c2ecf20Sopenharmony_ci pwr_on = MS_POWER_ON; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 1158c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 1168c2ecf20Sopenharmony_ci pwr_mask, partial_pwr_on); 1178c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 1188c2ecf20Sopenharmony_ci LDO3318_PWR_MASK, 0x04); 1198c2ecf20Sopenharmony_ci err = rtsx_pci_send_cmd(pcr, 100); 1208c2ecf20Sopenharmony_ci if (err < 0) 1218c2ecf20Sopenharmony_ci return err; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* To avoid too large in-rush current */ 1248c2ecf20Sopenharmony_ci udelay(150); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 1278c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on); 1288c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 1298c2ecf20Sopenharmony_ci LDO3318_PWR_MASK, 0x00); 1308c2ecf20Sopenharmony_ci return rtsx_pci_send_cmd(pcr, 100); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci u8 pwr_mask, pwr_off; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci pwr_mask = SD_POWER_MASK; 1388c2ecf20Sopenharmony_ci pwr_off = SD_POWER_OFF; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { 1418c2ecf20Sopenharmony_ci pwr_mask = MS_POWER_MASK; 1428c2ecf20Sopenharmony_ci pwr_off = MS_POWER_OFF; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 1468c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 1478c2ecf20Sopenharmony_ci pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA); 1488c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 1498c2ecf20Sopenharmony_ci LDO3318_PWR_MASK, 0x06); 1508c2ecf20Sopenharmony_ci return rtsx_pci_send_cmd(pcr, 100); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci int err; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (voltage == OUTPUT_3V3) { 1588c2ecf20Sopenharmony_ci err = rtsx_pci_write_register(pcr, 1598c2ecf20Sopenharmony_ci SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); 1608c2ecf20Sopenharmony_ci if (err < 0) 1618c2ecf20Sopenharmony_ci return err; 1628c2ecf20Sopenharmony_ci err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); 1638c2ecf20Sopenharmony_ci if (err < 0) 1648c2ecf20Sopenharmony_ci return err; 1658c2ecf20Sopenharmony_ci } else if (voltage == OUTPUT_1V8) { 1668c2ecf20Sopenharmony_ci err = rtsx_pci_write_register(pcr, 1678c2ecf20Sopenharmony_ci SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); 1688c2ecf20Sopenharmony_ci if (err < 0) 1698c2ecf20Sopenharmony_ci return err; 1708c2ecf20Sopenharmony_ci err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); 1718c2ecf20Sopenharmony_ci if (err < 0) 1728c2ecf20Sopenharmony_ci return err; 1738c2ecf20Sopenharmony_ci } else { 1748c2ecf20Sopenharmony_ci return -EINVAL; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic const struct pcr_ops rts5209_pcr_ops = { 1818c2ecf20Sopenharmony_ci .fetch_vendor_settings = rts5209_fetch_vendor_settings, 1828c2ecf20Sopenharmony_ci .extra_init_hw = rts5209_extra_init_hw, 1838c2ecf20Sopenharmony_ci .optimize_phy = rts5209_optimize_phy, 1848c2ecf20Sopenharmony_ci .turn_on_led = rts5209_turn_on_led, 1858c2ecf20Sopenharmony_ci .turn_off_led = rts5209_turn_off_led, 1868c2ecf20Sopenharmony_ci .enable_auto_blink = rts5209_enable_auto_blink, 1878c2ecf20Sopenharmony_ci .disable_auto_blink = rts5209_disable_auto_blink, 1888c2ecf20Sopenharmony_ci .card_power_on = rts5209_card_power_on, 1898c2ecf20Sopenharmony_ci .card_power_off = rts5209_card_power_off, 1908c2ecf20Sopenharmony_ci .switch_output_voltage = rts5209_switch_output_voltage, 1918c2ecf20Sopenharmony_ci .cd_deglitch = NULL, 1928c2ecf20Sopenharmony_ci .conv_clk_and_div_n = NULL, 1938c2ecf20Sopenharmony_ci .force_power_down = rts5209_force_power_down, 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* SD Pull Control Enable: 1978c2ecf20Sopenharmony_ci * SD_DAT[3:0] ==> pull up 1988c2ecf20Sopenharmony_ci * SD_CD ==> pull up 1998c2ecf20Sopenharmony_ci * SD_WP ==> pull up 2008c2ecf20Sopenharmony_ci * SD_CMD ==> pull up 2018c2ecf20Sopenharmony_ci * SD_CLK ==> pull down 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_cistatic const u32 rts5209_sd_pull_ctl_enable_tbl[] = { 2048c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), 2058c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), 2068c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), 2078c2ecf20Sopenharmony_ci 0, 2088c2ecf20Sopenharmony_ci}; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* SD Pull Control Disable: 2118c2ecf20Sopenharmony_ci * SD_DAT[3:0] ==> pull down 2128c2ecf20Sopenharmony_ci * SD_CD ==> pull up 2138c2ecf20Sopenharmony_ci * SD_WP ==> pull down 2148c2ecf20Sopenharmony_ci * SD_CMD ==> pull down 2158c2ecf20Sopenharmony_ci * SD_CLK ==> pull down 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_cistatic const u32 rts5209_sd_pull_ctl_disable_tbl[] = { 2188c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55), 2198c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), 2208c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), 2218c2ecf20Sopenharmony_ci 0, 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* MS Pull Control Enable: 2258c2ecf20Sopenharmony_ci * MS CD ==> pull up 2268c2ecf20Sopenharmony_ci * others ==> pull down 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic const u32 rts5209_ms_pull_ctl_enable_tbl[] = { 2298c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), 2308c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), 2318c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), 2328c2ecf20Sopenharmony_ci 0, 2338c2ecf20Sopenharmony_ci}; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* MS Pull Control Disable: 2368c2ecf20Sopenharmony_ci * MS CD ==> pull up 2378c2ecf20Sopenharmony_ci * others ==> pull down 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic const u32 rts5209_ms_pull_ctl_disable_tbl[] = { 2408c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), 2418c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), 2428c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), 2438c2ecf20Sopenharmony_ci 0, 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_civoid rts5209_init_params(struct rtsx_pcr *pcr) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | 2498c2ecf20Sopenharmony_ci EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT; 2508c2ecf20Sopenharmony_ci pcr->num_slots = 2; 2518c2ecf20Sopenharmony_ci pcr->ops = &rts5209_pcr_ops; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci pcr->flags = 0; 2548c2ecf20Sopenharmony_ci pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT; 2558c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; 2568c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; 2578c2ecf20Sopenharmony_ci pcr->aspm_en = ASPM_L1_EN; 2588c2ecf20Sopenharmony_ci pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16); 2598c2ecf20Sopenharmony_ci pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci pcr->ic_version = rts5209_get_ic_version(pcr); 2628c2ecf20Sopenharmony_ci pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; 2638c2ecf20Sopenharmony_ci pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl; 2648c2ecf20Sopenharmony_ci pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl; 2658c2ecf20Sopenharmony_ci pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl; 2668c2ecf20Sopenharmony_ci} 267