linux/drivers/mfd/rts5249.c
<<
>>
Prefs
   1/* Driver for Realtek PCI-Express card reader
   2 *
   3 * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License as published by the
   7 * Free Software Foundation; either version 2, or (at your option) any
   8 * later version.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along
  16 * with this program; if not, see <http://www.gnu.org/licenses/>.
  17 *
  18 * Author:
  19 *   Wei WANG <wei_wang@realsil.com.cn>
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/delay.h>
  24#include <linux/mfd/rtsx_pci.h>
  25
  26#include "rtsx_pcr.h"
  27
  28static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr)
  29{
  30        u8 val;
  31
  32        rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
  33        return val & 0x0F;
  34}
  35
  36static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
  37{
  38        u8 driving_3v3[4][3] = {
  39                {0x11, 0x11, 0x11},
  40                {0x55, 0x55, 0x5C},
  41                {0x99, 0x99, 0x92},
  42                {0x99, 0x99, 0x92},
  43        };
  44        u8 driving_1v8[4][3] = {
  45                {0x3C, 0x3C, 0x3C},
  46                {0xB3, 0xB3, 0xB3},
  47                {0xFE, 0xFE, 0xFE},
  48                {0xC4, 0xC4, 0xC4},
  49        };
  50        u8 (*driving)[3], drive_sel;
  51
  52        if (voltage == OUTPUT_3V3) {
  53                driving = driving_3v3;
  54                drive_sel = pcr->sd30_drive_sel_3v3;
  55        } else {
  56                driving = driving_1v8;
  57                drive_sel = pcr->sd30_drive_sel_1v8;
  58        }
  59
  60        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
  61                        0xFF, driving[drive_sel][0]);
  62        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
  63                        0xFF, driving[drive_sel][1]);
  64        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
  65                        0xFF, driving[drive_sel][2]);
  66}
  67
  68static void rts5249_fetch_vendor_settings(struct rtsx_pcr *pcr)
  69{
  70        u32 reg;
  71
  72        rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
  73        dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
  74
  75        if (!rtsx_vendor_setting_valid(reg))
  76                return;
  77
  78        pcr->aspm_en = rtsx_reg_to_aspm(reg);
  79        pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
  80        pcr->card_drive_sel &= 0x3F;
  81        pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
  82
  83        rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
  84        dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
  85        pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
  86        if (rtsx_reg_check_reverse_socket(reg))
  87                pcr->flags |= PCR_REVERSE_SOCKET;
  88}
  89
  90static void rts5249_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
  91{
  92        /* Set relink_time to 0 */
  93        rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0);
  94        rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0);
  95        rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0);
  96
  97        if (pm_state == HOST_ENTER_S3)
  98                rtsx_pci_write_register(pcr, PM_CTRL3, 0x10, 0x10);
  99
 100        rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
 101}
 102
 103static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
 104{
 105        rtsx_pci_init_cmd(pcr);
 106
 107        /* Configure GPIO as output */
 108        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
 109        /* Reset ASPM state to default value */
 110        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
 111        /* Switch LDO3318 source from DV33 to card_3v3 */
 112        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
 113        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
 114        /* LED shine disabled, set initial shine cycle period */
 115        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
 116        /* Configure driving */
 117        rts5249_fill_driving(pcr, OUTPUT_3V3);
 118        if (pcr->flags & PCR_REVERSE_SOCKET)
 119                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
 120                                AUTOLOAD_CFG_BASE + 3, 0xB0, 0xB0);
 121        else
 122                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
 123                                AUTOLOAD_CFG_BASE + 3, 0xB0, 0x80);
 124        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x10, 0x00);
 125
 126        return rtsx_pci_send_cmd(pcr, 100);
 127}
 128
 129static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
 130{
 131        int err;
 132
 133        err = rtsx_pci_write_phy_register(pcr, PHY_REG_REV, 0xFE46);
 134        if (err < 0)
 135                return err;
 136
 137        msleep(1);
 138
 139        return rtsx_pci_write_phy_register(pcr, PHY_BPCR, 0x05C0);
 140}
 141
 142static int rts5249_turn_on_led(struct rtsx_pcr *pcr)
 143{
 144        return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
 145}
 146
 147static int rts5249_turn_off_led(struct rtsx_pcr *pcr)
 148{
 149        return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
 150}
 151
 152static int rts5249_enable_auto_blink(struct rtsx_pcr *pcr)
 153{
 154        return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
 155}
 156
 157static int rts5249_disable_auto_blink(struct rtsx_pcr *pcr)
 158{
 159        return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
 160}
 161
 162static int rts5249_card_power_on(struct rtsx_pcr *pcr, int card)
 163{
 164        int err;
 165
 166        rtsx_pci_init_cmd(pcr);
 167        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 168                        SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON);
 169        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 170                        LDO3318_PWR_MASK, 0x02);
 171        err = rtsx_pci_send_cmd(pcr, 100);
 172        if (err < 0)
 173                return err;
 174
 175        msleep(5);
 176
 177        rtsx_pci_init_cmd(pcr);
 178        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 179                        SD_POWER_MASK, SD_VCC_POWER_ON);
 180        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 181                        LDO3318_PWR_MASK, 0x06);
 182        err = rtsx_pci_send_cmd(pcr, 100);
 183        if (err < 0)
 184                return err;
 185
 186        return 0;
 187}
 188
 189static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card)
 190{
 191        rtsx_pci_init_cmd(pcr);
 192        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
 193                        SD_POWER_MASK, SD_POWER_OFF);
 194        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
 195                        LDO3318_PWR_MASK, 0x00);
 196        return rtsx_pci_send_cmd(pcr, 100);
 197}
 198
 199static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 200{
 201        int err;
 202
 203        if (voltage == OUTPUT_3V3) {
 204                err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24);
 205                if (err < 0)
 206                        return err;
 207        } else if (voltage == OUTPUT_1V8) {
 208                err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02);
 209                if (err < 0)
 210                        return err;
 211                err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24);
 212                if (err < 0)
 213                        return err;
 214        } else {
 215                return -EINVAL;
 216        }
 217
 218        /* set pad drive */
 219        rtsx_pci_init_cmd(pcr);
 220        rts5249_fill_driving(pcr, voltage);
 221        return rtsx_pci_send_cmd(pcr, 100);
 222}
 223
 224static const struct pcr_ops rts5249_pcr_ops = {
 225        .fetch_vendor_settings = rts5249_fetch_vendor_settings,
 226        .extra_init_hw = rts5249_extra_init_hw,
 227        .optimize_phy = rts5249_optimize_phy,
 228        .turn_on_led = rts5249_turn_on_led,
 229        .turn_off_led = rts5249_turn_off_led,
 230        .enable_auto_blink = rts5249_enable_auto_blink,
 231        .disable_auto_blink = rts5249_disable_auto_blink,
 232        .card_power_on = rts5249_card_power_on,
 233        .card_power_off = rts5249_card_power_off,
 234        .switch_output_voltage = rts5249_switch_output_voltage,
 235        .force_power_down = rts5249_force_power_down,
 236};
 237
 238/* SD Pull Control Enable:
 239 *     SD_DAT[3:0] ==> pull up
 240 *     SD_CD       ==> pull up
 241 *     SD_WP       ==> pull up
 242 *     SD_CMD      ==> pull up
 243 *     SD_CLK      ==> pull down
 244 */
 245static const u32 rts5249_sd_pull_ctl_enable_tbl[] = {
 246        RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
 247        RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
 248        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
 249        RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA),
 250        0,
 251};
 252
 253/* SD Pull Control Disable:
 254 *     SD_DAT[3:0] ==> pull down
 255 *     SD_CD       ==> pull up
 256 *     SD_WP       ==> pull down
 257 *     SD_CMD      ==> pull down
 258 *     SD_CLK      ==> pull down
 259 */
 260static const u32 rts5249_sd_pull_ctl_disable_tbl[] = {
 261        RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66),
 262        RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
 263        RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
 264        RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
 265        0,
 266};
 267
 268/* MS Pull Control Enable:
 269 *     MS CD       ==> pull up
 270 *     others      ==> pull down
 271 */
 272static const u32 rts5249_ms_pull_ctl_enable_tbl[] = {
 273        RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
 274        RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
 275        RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
 276        0,
 277};
 278
 279/* MS Pull Control Disable:
 280 *     MS CD       ==> pull up
 281 *     others      ==> pull down
 282 */
 283static const u32 rts5249_ms_pull_ctl_disable_tbl[] = {
 284        RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55),
 285        RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
 286        RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
 287        0,
 288};
 289
 290void rts5249_init_params(struct rtsx_pcr *pcr)
 291{
 292        pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
 293        pcr->num_slots = 2;
 294        pcr->ops = &rts5249_pcr_ops;
 295
 296        pcr->flags = 0;
 297        pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
 298        pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_C;
 299        pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
 300        pcr->aspm_en = ASPM_L1_EN;
 301        pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
 302        pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 303
 304        pcr->ic_version = rts5249_get_ic_version(pcr);
 305        pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl;
 306        pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl;
 307        pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl;
 308        pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl;
 309}
 310
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.