linux/drivers/misc/cardreader/rts5209.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Driver for Realtek PCI-Express card reader
   3 *
   4 * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
   5 *
   6 * Author:
   7 *   Wei WANG <wei_wang@realsil.com.cn>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/delay.h>
  12#include <linux/rtsx_pci.h>
  13
  14#include "rtsx_pcr.h"
  15
  16static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr)
  17{
  18        u8 val;
  19
  20        val = rtsx_pci_readb(pcr, 0x1C);
  21        return val & 0x0F;
  22}
  23
  24static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
  25{
  26        struct pci_dev *pdev = pcr->pci;
  27        u32 reg;
  28
  29        pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
  30        pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
  31
  32        if (rts5209_vendor_setting1_valid(reg)) {
  33                if (rts5209_reg_check_ms_pmos(reg))
  34                        pcr->flags |= PCR_MS_PMOS;
  35                pcr->aspm_en = rts5209_reg_to_aspm(reg);
  36        }
  37
  38        pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
  39        pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
  40
  41        if (rts5209_vendor_setting2_valid(reg)) {
  42                pcr->sd30_drive_sel_1v8 =
  43                        rts5209_reg_to_sd30_drive_sel_1v8(reg);
  44                pcr->sd30_drive_sel_3v3 =
  45                        rts5209_reg_to_sd30_drive_sel_3v3(reg);
  46                pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg);
  47        }
  48}
  49
  50static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
  51{
  52        rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
  53}
  54
  55static int rts5209_extra_init_hw(struct rtsx_pcr *pcr)
  56{
  57        rtsx_pci_init_cmd(pcr);
  58
  59        /* Turn off LED */
  60        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03);
  61        /* Reset ASPM state to default value */
  62        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
  63        /* Force CLKREQ# PIN to drive 0 to request clock */
  64        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
  65        /* Configure GPIO as output */
  66        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03);
  67        /* Configure driving */
  68        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
  69                        0xFF, pcr->sd30_drive_sel_3v3);
  70
  71        return rtsx_pci_send_cmd(pcr, 100);
  72}
  73
  74static int rts5209_optimize_phy(struct rtsx_pcr *pcr)
  75{
  76        return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966);
  77}
  78
  79static int rts5209_turn_on_led(struct rtsx_pcr *pcr)
  80{
  81        return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
  82}
  83
  84static int rts5209_turn_off_led(struct rtsx_pcr *pcr)
  85{
  86        return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01);
  87}
  88
  89static int rts5209_enable_auto_blink(struct rtsx_pcr *pcr)
  90{
  91        return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D);
  92}
  93
  94static int rts5209_disable_auto_blink(struct rtsx_pcr *pcr)
  95{
  96        return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00);
  97}
  98
  99static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card)
 100{
 101        int err;
 102        u8 pwr_mask, partial_pwr_on, pwr_on;
 103
 104        pwr_mask = SD_POWER_MASK;
 105        partial_pwr_on = SD_PARTIAL_POWER_ON;
 106        pwr_on = SD_POWER_ON;
 107
 108        if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
 109                pwr_mask = MS_POWER_MASK;
 110                partial_pwr_on = MS_PARTIAL_POWER_ON;
 111                pwr_on = MS_POWER_ON;
 112        }
 113
 114        rtsx_pci_init_cmd(pcr);
 115        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 116                        pwr_mask, partial_pwr_on);
 117        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 118                        LDO3318_PWR_MASK, 0x04);
 119        err = rtsx_pci_send_cmd(pcr, 100);
 120        if (err < 0)
 121                return err;
 122
 123        /* To avoid too large in-rush current */
 124        udelay(150);
 125
 126        rtsx_pci_init_cmd(pcr);
 127        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on);
 128        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 129                        LDO3318_PWR_MASK, 0x00);
 130        return rtsx_pci_send_cmd(pcr, 100);
 131}
 132
 133static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card)
 134{
 135        u8 pwr_mask, pwr_off;
 136
 137        pwr_mask = SD_POWER_MASK;
 138        pwr_off = SD_POWER_OFF;
 139
 140        if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
 141                pwr_mask = MS_POWER_MASK;
 142                pwr_off = MS_POWER_OFF;
 143        }
 144
 145        rtsx_pci_init_cmd(pcr);
 146        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 147                        pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA);
 148        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 149                        LDO3318_PWR_MASK, 0x06);
 150        return rtsx_pci_send_cmd(pcr, 100);
 151}
 152
 153static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 154{
 155        int err;
 156
 157        if (voltage == OUTPUT_3V3) {
 158                err = rtsx_pci_write_register(pcr,
 159                                SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
 160                if (err < 0)
 161                        return err;
 162                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
 163                if (err < 0)
 164                        return err;
 165        } else if (voltage == OUTPUT_1V8) {
 166                err = rtsx_pci_write_register(pcr,
 167                                SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
 168                if (err < 0)
 169                        return err;
 170                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
 171                if (err < 0)
 172                        return err;
 173        } else {
 174                return -EINVAL;
 175        }
 176
 177        return 0;
 178}
 179
 180static const struct pcr_ops rts5209_pcr_ops = {
 181        .fetch_vendor_settings = rts5209_fetch_vendor_settings,
 182        .extra_init_hw = rts5209_extra_init_hw,
 183        .optimize_phy = rts5209_optimize_phy,
 184        .turn_on_led = rts5209_turn_on_led,
 185        .turn_off_led = rts5209_turn_off_led,
 186        .enable_auto_blink = rts5209_enable_auto_blink,
 187        .disable_auto_blink = rts5209_disable_auto_blink,
 188        .card_power_on = rts5209_card_power_on,
 189        .card_power_off = rts5209_card_power_off,
 190        .switch_output_voltage = rts5209_switch_output_voltage,
 191        .cd_deglitch = NULL,
 192        .conv_clk_and_div_n = NULL,
 193        .force_power_down = rts5209_force_power_down,
 194};
 195
 196/* SD Pull Control Enable:
 197 *     SD_DAT[3:0] ==> pull up
 198 *     SD_CD       ==> pull up
 199 *     SD_WP       ==> pull up
 200 *     SD_CMD      ==> pull up
 201 *     SD_CLK      ==> pull down
 202 */
 203static const u32 rts5209_sd_pull_ctl_enable_tbl[] = {
 204        RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
 205        RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
 206        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
 207        0,
 208};
 209
 210/* SD Pull Control Disable:
 211 *     SD_DAT[3:0] ==> pull down
 212 *     SD_CD       ==> pull up
 213 *     SD_WP       ==> pull down
 214 *     SD_CMD      ==> pull down
 215 *     SD_CLK      ==> pull down
 216 */
 217static const u32 rts5209_sd_pull_ctl_disable_tbl[] = {
 218        RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55),
 219        RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
 220        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
 221        0,
 222};
 223
 224/* MS Pull Control Enable:
 225 *     MS CD       ==> pull up
 226 *     others      ==> pull down
 227 */
 228static const u32 rts5209_ms_pull_ctl_enable_tbl[] = {
 229        RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
 230        RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
 231        RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
 232        0,
 233};
 234
 235/* MS Pull Control Disable:
 236 *     MS CD       ==> pull up
 237 *     others      ==> pull down
 238 */
 239static const u32 rts5209_ms_pull_ctl_disable_tbl[] = {
 240        RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
 241        RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
 242        RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
 243        0,
 244};
 245
 246void rts5209_init_params(struct rtsx_pcr *pcr)
 247{
 248        pcr->extra_caps = EXTRA_CAPS_SD_SDR50 |
 249                EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT;
 250        pcr->num_slots = 2;
 251        pcr->ops = &rts5209_pcr_ops;
 252
 253        pcr->flags = 0;
 254        pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT;
 255        pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
 256        pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
 257        pcr->aspm_en = ASPM_L1_EN;
 258        pcr->aspm_mode = ASPM_MODE_CFG;
 259        pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16);
 260        pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 261
 262        pcr->ic_version = rts5209_get_ic_version(pcr);
 263        pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl;
 264        pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl;
 265        pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl;
 266        pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl;
 267}
 268