linux/drivers/misc/cardreader/rts5229.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 rts5229_get_ic_version(struct rtsx_pcr *pcr)
  17{
  18        u8 val;
  19
  20        rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
  21        return val & 0x0F;
  22}
  23
  24static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
  25{
  26        u32 reg;
  27
  28        rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
  29        pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
  30
  31        if (!rtsx_vendor_setting_valid(reg))
  32                return;
  33
  34        pcr->aspm_en = rtsx_reg_to_aspm(reg);
  35        pcr->sd30_drive_sel_1v8 =
  36                map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg));
  37        pcr->card_drive_sel &= 0x3F;
  38        pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
  39
  40        rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
  41        pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
  42        pcr->sd30_drive_sel_3v3 =
  43                map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
  44}
  45
  46static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
  47{
  48        rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
  49}
  50
  51static int rts5229_extra_init_hw(struct rtsx_pcr *pcr)
  52{
  53        rtsx_pci_init_cmd(pcr);
  54
  55        /* Configure GPIO as output */
  56        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
  57        /* Reset ASPM state to default value */
  58        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
  59        /* Force CLKREQ# PIN to drive 0 to request clock */
  60        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
  61        /* Switch LDO3318 source from DV33 to card_3v3 */
  62        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
  63        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
  64        /* LED shine disabled, set initial shine cycle period */
  65        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
  66        /* Configure driving */
  67        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
  68                        0xFF, pcr->sd30_drive_sel_3v3);
  69
  70        return rtsx_pci_send_cmd(pcr, 100);
  71}
  72
  73static int rts5229_optimize_phy(struct rtsx_pcr *pcr)
  74{
  75        /* Optimize RX sensitivity */
  76        return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
  77}
  78
  79static int rts5229_turn_on_led(struct rtsx_pcr *pcr)
  80{
  81        return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
  82}
  83
  84static int rts5229_turn_off_led(struct rtsx_pcr *pcr)
  85{
  86        return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
  87}
  88
  89static int rts5229_enable_auto_blink(struct rtsx_pcr *pcr)
  90{
  91        return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
  92}
  93
  94static int rts5229_disable_auto_blink(struct rtsx_pcr *pcr)
  95{
  96        return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
  97}
  98
  99static int rts5229_card_power_on(struct rtsx_pcr *pcr, int card)
 100{
 101        int err;
 102
 103        rtsx_pci_init_cmd(pcr);
 104        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 105                        SD_POWER_MASK, SD_PARTIAL_POWER_ON);
 106        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 107                        LDO3318_PWR_MASK, 0x02);
 108        err = rtsx_pci_send_cmd(pcr, 100);
 109        if (err < 0)
 110                return err;
 111
 112        /* To avoid too large in-rush current */
 113        udelay(150);
 114
 115        rtsx_pci_init_cmd(pcr);
 116        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 117                        SD_POWER_MASK, SD_POWER_ON);
 118        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 119                        LDO3318_PWR_MASK, 0x06);
 120        return rtsx_pci_send_cmd(pcr, 100);
 121}
 122
 123static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card)
 124{
 125        rtsx_pci_init_cmd(pcr);
 126        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 127                        SD_POWER_MASK | PMOS_STRG_MASK,
 128                        SD_POWER_OFF | PMOS_STRG_400mA);
 129        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 130                        LDO3318_PWR_MASK, 0x00);
 131        return rtsx_pci_send_cmd(pcr, 100);
 132}
 133
 134static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 135{
 136        int err;
 137
 138        if (voltage == OUTPUT_3V3) {
 139                err = rtsx_pci_write_register(pcr,
 140                                SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
 141                if (err < 0)
 142                        return err;
 143                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
 144                if (err < 0)
 145                        return err;
 146        } else if (voltage == OUTPUT_1V8) {
 147                err = rtsx_pci_write_register(pcr,
 148                                SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
 149                if (err < 0)
 150                        return err;
 151                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
 152                if (err < 0)
 153                        return err;
 154        } else {
 155                return -EINVAL;
 156        }
 157
 158        return 0;
 159}
 160
 161static const struct pcr_ops rts5229_pcr_ops = {
 162        .fetch_vendor_settings = rts5229_fetch_vendor_settings,
 163        .extra_init_hw = rts5229_extra_init_hw,
 164        .optimize_phy = rts5229_optimize_phy,
 165        .turn_on_led = rts5229_turn_on_led,
 166        .turn_off_led = rts5229_turn_off_led,
 167        .enable_auto_blink = rts5229_enable_auto_blink,
 168        .disable_auto_blink = rts5229_disable_auto_blink,
 169        .card_power_on = rts5229_card_power_on,
 170        .card_power_off = rts5229_card_power_off,
 171        .switch_output_voltage = rts5229_switch_output_voltage,
 172        .cd_deglitch = NULL,
 173        .conv_clk_and_div_n = NULL,
 174        .force_power_down = rts5229_force_power_down,
 175};
 176
 177/* SD Pull Control Enable:
 178 *     SD_DAT[3:0] ==> pull up
 179 *     SD_CD       ==> pull up
 180 *     SD_WP       ==> pull up
 181 *     SD_CMD      ==> pull up
 182 *     SD_CLK      ==> pull down
 183 */
 184static const u32 rts5229_sd_pull_ctl_enable_tbl1[] = {
 185        RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
 186        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
 187        0,
 188};
 189
 190/* For RTS5229 version C */
 191static const u32 rts5229_sd_pull_ctl_enable_tbl2[] = {
 192        RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
 193        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9),
 194        0,
 195};
 196
 197/* SD Pull Control Disable:
 198 *     SD_DAT[3:0] ==> pull down
 199 *     SD_CD       ==> pull up
 200 *     SD_WP       ==> pull down
 201 *     SD_CMD      ==> pull down
 202 *     SD_CLK      ==> pull down
 203 */
 204static const u32 rts5229_sd_pull_ctl_disable_tbl1[] = {
 205        RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
 206        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
 207        0,
 208};
 209
 210/* For RTS5229 version C */
 211static const u32 rts5229_sd_pull_ctl_disable_tbl2[] = {
 212        RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
 213        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5),
 214        0,
 215};
 216
 217/* MS Pull Control Enable:
 218 *     MS CD       ==> pull up
 219 *     others      ==> pull down
 220 */
 221static const u32 rts5229_ms_pull_ctl_enable_tbl[] = {
 222        RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
 223        RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
 224        0,
 225};
 226
 227/* MS Pull Control Disable:
 228 *     MS CD       ==> pull up
 229 *     others      ==> pull down
 230 */
 231static const u32 rts5229_ms_pull_ctl_disable_tbl[] = {
 232        RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
 233        RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
 234        0,
 235};
 236
 237void rts5229_init_params(struct rtsx_pcr *pcr)
 238{
 239        pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
 240        pcr->num_slots = 2;
 241        pcr->ops = &rts5229_pcr_ops;
 242
 243        pcr->flags = 0;
 244        pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
 245        pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
 246        pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
 247        pcr->aspm_en = ASPM_L1_EN;
 248        pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15);
 249        pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6);
 250
 251        pcr->ic_version = rts5229_get_ic_version(pcr);
 252        if (pcr->ic_version == IC_VER_C) {
 253                pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2;
 254                pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2;
 255        } else {
 256                pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1;
 257                pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1;
 258        }
 259        pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl;
 260        pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl;
 261}
 262