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.8-rc7 280 lines 7.6 kB view raw
1/* Driver for Realtek PCI-Express card reader 2 * 3 * Copyright(c) 2009 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 * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China 21 */ 22 23#include <linux/module.h> 24#include <linux/bitops.h> 25#include <linux/delay.h> 26#include <linux/mfd/rtsx_pci.h> 27 28#include "rtsx_pcr.h" 29 30static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr) 31{ 32 u8 val; 33 34 rtsx_pci_read_register(pcr, SYS_VER, &val); 35 return val & 0x0F; 36} 37 38static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) 39{ 40 return rtsx_pci_write_register(pcr, CD_PAD_CTL, 41 CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); 42} 43 44static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) 45{ 46 return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); 47} 48 49static int rtl8411_turn_off_led(struct rtsx_pcr *pcr) 50{ 51 return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); 52} 53 54static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr) 55{ 56 return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); 57} 58 59static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr) 60{ 61 return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); 62} 63 64static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card) 65{ 66 int err; 67 68 rtsx_pci_init_cmd(pcr); 69 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, 70 BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); 71 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL, 72 BPP_LDO_POWB, BPP_LDO_SUSPEND); 73 err = rtsx_pci_send_cmd(pcr, 100); 74 if (err < 0) 75 return err; 76 77 /* To avoid too large in-rush current */ 78 udelay(150); 79 80 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, 81 BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON); 82 if (err < 0) 83 return err; 84 85 udelay(150); 86 87 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, 88 BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON); 89 if (err < 0) 90 return err; 91 92 udelay(150); 93 94 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, 95 BPP_POWER_MASK, BPP_POWER_ON); 96 if (err < 0) 97 return err; 98 99 return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON); 100} 101 102static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card) 103{ 104 int err; 105 106 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, 107 BPP_POWER_MASK, BPP_POWER_OFF); 108 if (err < 0) 109 return err; 110 111 return rtsx_pci_write_register(pcr, LDO_CTL, 112 BPP_LDO_POWB, BPP_LDO_SUSPEND); 113} 114 115static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) 116{ 117 u8 mask, val; 118 119 mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK; 120 if (voltage == OUTPUT_3V3) 121 val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3; 122 else if (voltage == OUTPUT_1V8) 123 val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8; 124 else 125 return -EINVAL; 126 127 return rtsx_pci_write_register(pcr, LDO_CTL, mask, val); 128} 129 130static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr) 131{ 132 unsigned int card_exist; 133 134 card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); 135 card_exist &= CARD_EXIST; 136 if (!card_exist) { 137 /* Enable card CD */ 138 rtsx_pci_write_register(pcr, CD_PAD_CTL, 139 CD_DISABLE_MASK, CD_ENABLE); 140 /* Enable card interrupt */ 141 rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00); 142 return 0; 143 } 144 145 if (hweight32(card_exist) > 1) { 146 rtsx_pci_write_register(pcr, CARD_PWR_CTL, 147 BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); 148 msleep(100); 149 150 card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); 151 if (card_exist & MS_EXIST) 152 card_exist = MS_EXIST; 153 else if (card_exist & SD_EXIST) 154 card_exist = SD_EXIST; 155 else 156 card_exist = 0; 157 158 rtsx_pci_write_register(pcr, CARD_PWR_CTL, 159 BPP_POWER_MASK, BPP_POWER_OFF); 160 161 dev_dbg(&(pcr->pci->dev), 162 "After CD deglitch, card_exist = 0x%x\n", 163 card_exist); 164 } 165 166 if (card_exist & MS_EXIST) { 167 /* Disable SD interrupt */ 168 rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40); 169 rtsx_pci_write_register(pcr, CD_PAD_CTL, 170 CD_DISABLE_MASK, MS_CD_EN_ONLY); 171 } else if (card_exist & SD_EXIST) { 172 /* Disable MS interrupt */ 173 rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80); 174 rtsx_pci_write_register(pcr, CD_PAD_CTL, 175 CD_DISABLE_MASK, SD_CD_EN_ONLY); 176 } 177 178 return card_exist; 179} 180 181static int rtl8411_conv_clk_and_div_n(int input, int dir) 182{ 183 int output; 184 185 if (dir == CLK_TO_DIV_N) 186 output = input * 4 / 5 - 2; 187 else 188 output = (input + 2) * 5 / 4; 189 190 return output; 191} 192 193static const struct pcr_ops rtl8411_pcr_ops = { 194 .extra_init_hw = rtl8411_extra_init_hw, 195 .optimize_phy = NULL, 196 .turn_on_led = rtl8411_turn_on_led, 197 .turn_off_led = rtl8411_turn_off_led, 198 .enable_auto_blink = rtl8411_enable_auto_blink, 199 .disable_auto_blink = rtl8411_disable_auto_blink, 200 .card_power_on = rtl8411_card_power_on, 201 .card_power_off = rtl8411_card_power_off, 202 .switch_output_voltage = rtl8411_switch_output_voltage, 203 .cd_deglitch = rtl8411_cd_deglitch, 204 .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, 205}; 206 207/* SD Pull Control Enable: 208 * SD_DAT[3:0] ==> pull up 209 * SD_CD ==> pull up 210 * SD_WP ==> pull up 211 * SD_CMD ==> pull up 212 * SD_CLK ==> pull down 213 */ 214static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = { 215 RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), 216 RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), 217 RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9), 218 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), 219 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09), 220 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), 221 0, 222}; 223 224/* SD Pull Control Disable: 225 * SD_DAT[3:0] ==> pull down 226 * SD_CD ==> pull up 227 * SD_WP ==> pull down 228 * SD_CMD ==> pull down 229 * SD_CLK ==> pull down 230 */ 231static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = { 232 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), 233 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), 234 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), 235 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), 236 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), 237 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), 238 0, 239}; 240 241/* MS Pull Control Enable: 242 * MS CD ==> pull up 243 * others ==> pull down 244 */ 245static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = { 246 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), 247 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), 248 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), 249 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05), 250 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), 251 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), 252 0, 253}; 254 255/* MS Pull Control Disable: 256 * MS CD ==> pull up 257 * others ==> pull down 258 */ 259static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = { 260 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), 261 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), 262 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), 263 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), 264 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), 265 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), 266 0, 267}; 268 269void rtl8411_init_params(struct rtsx_pcr *pcr) 270{ 271 pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; 272 pcr->num_slots = 2; 273 pcr->ops = &rtl8411_pcr_ops; 274 275 pcr->ic_version = rtl8411_get_ic_version(pcr); 276 pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl; 277 pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl; 278 pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl; 279 pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl; 280}