Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.15 353 lines 10 kB view raw
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, 134 PHY_REG_REV_RESV | PHY_REG_REV_RXIDLE_LATCHED | 135 PHY_REG_REV_P1_EN | PHY_REG_REV_RXIDLE_EN | 136 PHY_REG_REV_RX_PWST | PHY_REG_REV_CLKREQ_DLY_TIMER_1_0 | 137 PHY_REG_REV_STOP_CLKRD | PHY_REG_REV_STOP_CLKWR); 138 if (err < 0) 139 return err; 140 141 msleep(1); 142 143 err = rtsx_pci_write_phy_register(pcr, PHY_BPCR, 144 PHY_BPCR_IBRXSEL | PHY_BPCR_IBTXSEL | 145 PHY_BPCR_IB_FILTER | PHY_BPCR_CMIRROR_EN); 146 if (err < 0) 147 return err; 148 err = rtsx_pci_write_phy_register(pcr, PHY_PCR, 149 PHY_PCR_FORCE_CODE | PHY_PCR_OOBS_CALI_50 | 150 PHY_PCR_OOBS_VCM_08 | PHY_PCR_OOBS_SEN_90 | 151 PHY_PCR_RSSI_EN); 152 if (err < 0) 153 return err; 154 err = rtsx_pci_write_phy_register(pcr, PHY_RCR2, 155 PHY_RCR2_EMPHASE_EN | PHY_RCR2_NADJR | 156 PHY_RCR2_CDR_CP_10 | PHY_RCR2_CDR_SR_2 | 157 PHY_RCR2_FREQSEL_12 | PHY_RCR2_CPADJEN | 158 PHY_RCR2_CDR_SC_8 | PHY_RCR2_CALIB_LATE); 159 if (err < 0) 160 return err; 161 err = rtsx_pci_write_phy_register(pcr, PHY_FLD4, 162 PHY_FLD4_FLDEN_SEL | PHY_FLD4_REQ_REF | 163 PHY_FLD4_RXAMP_OFF | PHY_FLD4_REQ_ADDA | 164 PHY_FLD4_BER_COUNT | PHY_FLD4_BER_TIMER | 165 PHY_FLD4_BER_CHK_EN); 166 if (err < 0) 167 return err; 168 err = rtsx_pci_write_phy_register(pcr, PHY_RDR, PHY_RDR_RXDSEL_1_9); 169 if (err < 0) 170 return err; 171 err = rtsx_pci_write_phy_register(pcr, PHY_RCR1, 172 PHY_RCR1_ADP_TIME | PHY_RCR1_VCO_COARSE); 173 if (err < 0) 174 return err; 175 err = rtsx_pci_write_phy_register(pcr, PHY_FLD3, 176 PHY_FLD3_TIMER_4 | PHY_FLD3_TIMER_6 | 177 PHY_FLD3_RXDELINK); 178 if (err < 0) 179 return err; 180 return rtsx_pci_write_phy_register(pcr, PHY_TUNE, 181 PHY_TUNE_TUNEREF_1_0 | PHY_TUNE_VBGSEL_1252 | 182 PHY_TUNE_SDBUS_33 | PHY_TUNE_TUNED18 | 183 PHY_TUNE_TUNED12); 184} 185 186static int rts5249_turn_on_led(struct rtsx_pcr *pcr) 187{ 188 return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); 189} 190 191static int rts5249_turn_off_led(struct rtsx_pcr *pcr) 192{ 193 return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); 194} 195 196static int rts5249_enable_auto_blink(struct rtsx_pcr *pcr) 197{ 198 return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); 199} 200 201static int rts5249_disable_auto_blink(struct rtsx_pcr *pcr) 202{ 203 return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); 204} 205 206static int rts5249_card_power_on(struct rtsx_pcr *pcr, int card) 207{ 208 int err; 209 210 rtsx_pci_init_cmd(pcr); 211 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 212 SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON); 213 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 214 LDO3318_PWR_MASK, 0x02); 215 err = rtsx_pci_send_cmd(pcr, 100); 216 if (err < 0) 217 return err; 218 219 msleep(5); 220 221 rtsx_pci_init_cmd(pcr); 222 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 223 SD_POWER_MASK, SD_VCC_POWER_ON); 224 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 225 LDO3318_PWR_MASK, 0x06); 226 err = rtsx_pci_send_cmd(pcr, 100); 227 if (err < 0) 228 return err; 229 230 return 0; 231} 232 233static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card) 234{ 235 rtsx_pci_init_cmd(pcr); 236 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 237 SD_POWER_MASK, SD_POWER_OFF); 238 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, 239 LDO3318_PWR_MASK, 0x00); 240 return rtsx_pci_send_cmd(pcr, 100); 241} 242 243static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) 244{ 245 int err; 246 247 if (voltage == OUTPUT_3V3) { 248 err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24); 249 if (err < 0) 250 return err; 251 } else if (voltage == OUTPUT_1V8) { 252 err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02); 253 if (err < 0) 254 return err; 255 err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24); 256 if (err < 0) 257 return err; 258 } else { 259 return -EINVAL; 260 } 261 262 /* set pad drive */ 263 rtsx_pci_init_cmd(pcr); 264 rts5249_fill_driving(pcr, voltage); 265 return rtsx_pci_send_cmd(pcr, 100); 266} 267 268static const struct pcr_ops rts5249_pcr_ops = { 269 .fetch_vendor_settings = rts5249_fetch_vendor_settings, 270 .extra_init_hw = rts5249_extra_init_hw, 271 .optimize_phy = rts5249_optimize_phy, 272 .turn_on_led = rts5249_turn_on_led, 273 .turn_off_led = rts5249_turn_off_led, 274 .enable_auto_blink = rts5249_enable_auto_blink, 275 .disable_auto_blink = rts5249_disable_auto_blink, 276 .card_power_on = rts5249_card_power_on, 277 .card_power_off = rts5249_card_power_off, 278 .switch_output_voltage = rts5249_switch_output_voltage, 279 .force_power_down = rts5249_force_power_down, 280}; 281 282/* SD Pull Control Enable: 283 * SD_DAT[3:0] ==> pull up 284 * SD_CD ==> pull up 285 * SD_WP ==> pull up 286 * SD_CMD ==> pull up 287 * SD_CLK ==> pull down 288 */ 289static const u32 rts5249_sd_pull_ctl_enable_tbl[] = { 290 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), 291 RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), 292 RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), 293 RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA), 294 0, 295}; 296 297/* SD Pull Control Disable: 298 * SD_DAT[3:0] ==> pull down 299 * SD_CD ==> pull up 300 * SD_WP ==> pull down 301 * SD_CMD ==> pull down 302 * SD_CLK ==> pull down 303 */ 304static const u32 rts5249_sd_pull_ctl_disable_tbl[] = { 305 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), 306 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), 307 RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), 308 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), 309 0, 310}; 311 312/* MS Pull Control Enable: 313 * MS CD ==> pull up 314 * others ==> pull down 315 */ 316static const u32 rts5249_ms_pull_ctl_enable_tbl[] = { 317 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), 318 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), 319 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), 320 0, 321}; 322 323/* MS Pull Control Disable: 324 * MS CD ==> pull up 325 * others ==> pull down 326 */ 327static const u32 rts5249_ms_pull_ctl_disable_tbl[] = { 328 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), 329 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), 330 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), 331 0, 332}; 333 334void rts5249_init_params(struct rtsx_pcr *pcr) 335{ 336 pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; 337 pcr->num_slots = 2; 338 pcr->ops = &rts5249_pcr_ops; 339 340 pcr->flags = 0; 341 pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; 342 pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_C; 343 pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; 344 pcr->aspm_en = ASPM_L1_EN; 345 pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16); 346 pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); 347 348 pcr->ic_version = rts5249_get_ic_version(pcr); 349 pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; 350 pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl; 351 pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl; 352 pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl; 353}