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 rts5229_get_ic_version(struct rtsx_pcr *pcr) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci u8 val; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); 218c2ecf20Sopenharmony_ci return val & 0x0F; 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void rts5229_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 (!rtsx_vendor_setting_valid(reg)) 338c2ecf20Sopenharmony_ci return; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci pcr->aspm_en = rtsx_reg_to_aspm(reg); 368c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_1v8 = 378c2ecf20Sopenharmony_ci map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg)); 388c2ecf20Sopenharmony_ci pcr->card_drive_sel &= 0x3F; 398c2ecf20Sopenharmony_ci pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, PCR_SETTING_REG2, ®); 428c2ecf20Sopenharmony_ci pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); 438c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_3v3 = 448c2ecf20Sopenharmony_ci map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg)); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int rts5229_extra_init_hw(struct rtsx_pcr *pcr) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* Configure GPIO as output */ 578c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); 588c2ecf20Sopenharmony_ci /* Reset ASPM state to default value */ 598c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); 608c2ecf20Sopenharmony_ci /* Force CLKREQ# PIN to drive 0 to request clock */ 618c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); 628c2ecf20Sopenharmony_ci /* Switch LDO3318 source from DV33 to card_3v3 */ 638c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); 648c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); 658c2ecf20Sopenharmony_ci /* LED shine disabled, set initial shine cycle period */ 668c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); 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 rts5229_optimize_phy(struct rtsx_pcr *pcr) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci /* Optimize RX sensitivity */ 778c2ecf20Sopenharmony_ci return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int rts5229_turn_on_led(struct rtsx_pcr *pcr) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int rts5229_turn_off_led(struct rtsx_pcr *pcr) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int rts5229_enable_auto_blink(struct rtsx_pcr *pcr) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int rts5229_disable_auto_blink(struct rtsx_pcr *pcr) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int rts5229_card_power_on(struct rtsx_pcr *pcr, int card) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int err; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 1058c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 1068c2ecf20Sopenharmony_ci SD_POWER_MASK, SD_PARTIAL_POWER_ON); 1078c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 1088c2ecf20Sopenharmony_ci LDO3318_PWR_MASK, 0x02); 1098c2ecf20Sopenharmony_ci err = rtsx_pci_send_cmd(pcr, 100); 1108c2ecf20Sopenharmony_ci if (err < 0) 1118c2ecf20Sopenharmony_ci return err; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* To avoid too large in-rush current */ 1148c2ecf20Sopenharmony_ci udelay(150); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 1178c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 1188c2ecf20Sopenharmony_ci SD_POWER_MASK, SD_POWER_ON); 1198c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 1208c2ecf20Sopenharmony_ci LDO3318_PWR_MASK, 0x06); 1218c2ecf20Sopenharmony_ci return rtsx_pci_send_cmd(pcr, 100); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci rtsx_pci_init_cmd(pcr); 1278c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 1288c2ecf20Sopenharmony_ci SD_POWER_MASK | PMOS_STRG_MASK, 1298c2ecf20Sopenharmony_ci SD_POWER_OFF | PMOS_STRG_400mA); 1308c2ecf20Sopenharmony_ci rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 1318c2ecf20Sopenharmony_ci LDO3318_PWR_MASK, 0x00); 1328c2ecf20Sopenharmony_ci return rtsx_pci_send_cmd(pcr, 100); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int err; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (voltage == OUTPUT_3V3) { 1408c2ecf20Sopenharmony_ci err = rtsx_pci_write_register(pcr, 1418c2ecf20Sopenharmony_ci SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); 1428c2ecf20Sopenharmony_ci if (err < 0) 1438c2ecf20Sopenharmony_ci return err; 1448c2ecf20Sopenharmony_ci err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); 1458c2ecf20Sopenharmony_ci if (err < 0) 1468c2ecf20Sopenharmony_ci return err; 1478c2ecf20Sopenharmony_ci } else if (voltage == OUTPUT_1V8) { 1488c2ecf20Sopenharmony_ci err = rtsx_pci_write_register(pcr, 1498c2ecf20Sopenharmony_ci SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); 1508c2ecf20Sopenharmony_ci if (err < 0) 1518c2ecf20Sopenharmony_ci return err; 1528c2ecf20Sopenharmony_ci err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); 1538c2ecf20Sopenharmony_ci if (err < 0) 1548c2ecf20Sopenharmony_ci return err; 1558c2ecf20Sopenharmony_ci } else { 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic const struct pcr_ops rts5229_pcr_ops = { 1638c2ecf20Sopenharmony_ci .fetch_vendor_settings = rts5229_fetch_vendor_settings, 1648c2ecf20Sopenharmony_ci .extra_init_hw = rts5229_extra_init_hw, 1658c2ecf20Sopenharmony_ci .optimize_phy = rts5229_optimize_phy, 1668c2ecf20Sopenharmony_ci .turn_on_led = rts5229_turn_on_led, 1678c2ecf20Sopenharmony_ci .turn_off_led = rts5229_turn_off_led, 1688c2ecf20Sopenharmony_ci .enable_auto_blink = rts5229_enable_auto_blink, 1698c2ecf20Sopenharmony_ci .disable_auto_blink = rts5229_disable_auto_blink, 1708c2ecf20Sopenharmony_ci .card_power_on = rts5229_card_power_on, 1718c2ecf20Sopenharmony_ci .card_power_off = rts5229_card_power_off, 1728c2ecf20Sopenharmony_ci .switch_output_voltage = rts5229_switch_output_voltage, 1738c2ecf20Sopenharmony_ci .cd_deglitch = NULL, 1748c2ecf20Sopenharmony_ci .conv_clk_and_div_n = NULL, 1758c2ecf20Sopenharmony_ci .force_power_down = rts5229_force_power_down, 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* SD Pull Control Enable: 1798c2ecf20Sopenharmony_ci * SD_DAT[3:0] ==> pull up 1808c2ecf20Sopenharmony_ci * SD_CD ==> pull up 1818c2ecf20Sopenharmony_ci * SD_WP ==> pull up 1828c2ecf20Sopenharmony_ci * SD_CMD ==> pull up 1838c2ecf20Sopenharmony_ci * SD_CLK ==> pull down 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_cistatic const u32 rts5229_sd_pull_ctl_enable_tbl1[] = { 1868c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), 1878c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), 1888c2ecf20Sopenharmony_ci 0, 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* For RTS5229 version C */ 1928c2ecf20Sopenharmony_cistatic const u32 rts5229_sd_pull_ctl_enable_tbl2[] = { 1938c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), 1948c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9), 1958c2ecf20Sopenharmony_ci 0, 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* SD Pull Control Disable: 1998c2ecf20Sopenharmony_ci * SD_DAT[3:0] ==> pull down 2008c2ecf20Sopenharmony_ci * SD_CD ==> pull up 2018c2ecf20Sopenharmony_ci * SD_WP ==> pull down 2028c2ecf20Sopenharmony_ci * SD_CMD ==> pull down 2038c2ecf20Sopenharmony_ci * SD_CLK ==> pull down 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic const u32 rts5229_sd_pull_ctl_disable_tbl1[] = { 2068c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), 2078c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), 2088c2ecf20Sopenharmony_ci 0, 2098c2ecf20Sopenharmony_ci}; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* For RTS5229 version C */ 2128c2ecf20Sopenharmony_cistatic const u32 rts5229_sd_pull_ctl_disable_tbl2[] = { 2138c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), 2148c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5), 2158c2ecf20Sopenharmony_ci 0, 2168c2ecf20Sopenharmony_ci}; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* MS Pull Control Enable: 2198c2ecf20Sopenharmony_ci * MS CD ==> pull up 2208c2ecf20Sopenharmony_ci * others ==> pull down 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cistatic const u32 rts5229_ms_pull_ctl_enable_tbl[] = { 2238c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), 2248c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), 2258c2ecf20Sopenharmony_ci 0, 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* MS Pull Control Disable: 2298c2ecf20Sopenharmony_ci * MS CD ==> pull up 2308c2ecf20Sopenharmony_ci * others ==> pull down 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_cistatic const u32 rts5229_ms_pull_ctl_disable_tbl[] = { 2338c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), 2348c2ecf20Sopenharmony_ci RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), 2358c2ecf20Sopenharmony_ci 0, 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_civoid rts5229_init_params(struct rtsx_pcr *pcr) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; 2418c2ecf20Sopenharmony_ci pcr->num_slots = 2; 2428c2ecf20Sopenharmony_ci pcr->ops = &rts5229_pcr_ops; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci pcr->flags = 0; 2458c2ecf20Sopenharmony_ci pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; 2468c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; 2478c2ecf20Sopenharmony_ci pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; 2488c2ecf20Sopenharmony_ci pcr->aspm_en = ASPM_L1_EN; 2498c2ecf20Sopenharmony_ci pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15); 2508c2ecf20Sopenharmony_ci pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci pcr->ic_version = rts5229_get_ic_version(pcr); 2538c2ecf20Sopenharmony_ci if (pcr->ic_version == IC_VER_C) { 2548c2ecf20Sopenharmony_ci pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2; 2558c2ecf20Sopenharmony_ci pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2; 2568c2ecf20Sopenharmony_ci } else { 2578c2ecf20Sopenharmony_ci pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1; 2588c2ecf20Sopenharmony_ci pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl; 2618c2ecf20Sopenharmony_ci pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl; 2628c2ecf20Sopenharmony_ci} 263