1 /* 2 * Copyright (C) 2010 Google, Inc. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 15 #include <linux/err.h> 16 #include <linux/init.h> 17 #include <linux/platform_device.h> 18 #include <linux/clk.h> 19 #include <linux/io.h> 20 #include <linux/of.h> 21 #include <linux/of_gpio.h> 22 #include <linux/gpio.h> 23 #include <linux/mmc/card.h> 24 #include <linux/mmc/host.h> 25 26 #include <mach/gpio.h> 27 #include <mach/sdhci.h> 28 29 #include "sdhci-pltfm.h" 30 31 static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) 32 { 33 u32 val; 34 35 if (unlikely(reg == SDHCI_PRESENT_STATE)) { 36 /* Use wp_gpio here instead? */ 37 val = readl(host->ioaddr + reg); 38 return val | SDHCI_WRITE_PROTECT; 39 } 40 41 return readl(host->ioaddr + reg); 42 } 43 44 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) 45 { 46 if (unlikely(reg == SDHCI_HOST_VERSION)) { 47 /* Erratum: Version register is invalid in HW. */ 48 return SDHCI_SPEC_200; 49 } 50 51 return readw(host->ioaddr + reg); 52 } 53 54 static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) 55 { 56 /* Seems like we're getting spurious timeout and crc errors, so 57 * disable signalling of them. In case of real errors software 58 * timers should take care of eventually detecting them. 59 */ 60 if (unlikely(reg == SDHCI_SIGNAL_ENABLE)) 61 val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC); 62 63 writel(val, host->ioaddr + reg); 64 65 if (unlikely(reg == SDHCI_INT_ENABLE)) { 66 /* Erratum: Must enable block gap interrupt detection */ 67 u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 68 if (val & SDHCI_INT_CARD_INT) 69 gap_ctrl |= 0x8; 70 else 71 gap_ctrl &= ~0x8; 72 writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); 73 } 74 } 75 76 static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci) 77 { 78 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); 79 struct tegra_sdhci_platform_data *plat = pltfm_host->priv; 80 81 if (!gpio_is_valid(plat->wp_gpio)) 82 return -1; 83 84 return gpio_get_value(plat->wp_gpio); 85 } 86 87 static irqreturn_t carddetect_irq(int irq, void *data) 88 { 89 struct sdhci_host *sdhost = (struct sdhci_host *)data; 90 91 tasklet_schedule(&sdhost->card_tasklet); 92 return IRQ_HANDLED; 93 }; 94 95 static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) 96 { 97 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 98 struct tegra_sdhci_platform_data *plat = pltfm_host->priv; 99 u32 ctrl; 100 101 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 102 if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { 103 ctrl &= ~SDHCI_CTRL_4BITBUS; 104 ctrl |= SDHCI_CTRL_8BITBUS; 105 } else { 106 ctrl &= ~SDHCI_CTRL_8BITBUS; 107 if (bus_width == MMC_BUS_WIDTH_4) 108 ctrl |= SDHCI_CTRL_4BITBUS; 109 else 110 ctrl &= ~SDHCI_CTRL_4BITBUS; 111 } 112 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 113 return 0; 114 } 115 116 static struct sdhci_ops tegra_sdhci_ops = { 117 .get_ro = tegra_sdhci_get_ro, 118 .read_l = tegra_sdhci_readl, 119 .read_w = tegra_sdhci_readw, 120 .write_l = tegra_sdhci_writel, 121 .platform_8bit_width = tegra_sdhci_8bit, 122 }; 123 124 static struct sdhci_pltfm_data sdhci_tegra_pdata = { 125 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 126 SDHCI_QUIRK_SINGLE_POWER_WRITE | 127 SDHCI_QUIRK_NO_HISPD_BIT | 128 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, 129 .ops = &tegra_sdhci_ops, 130 }; 131 132 static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = { 133 { .compatible = "nvidia,tegra20-sdhci", }, 134 {} 135 }; 136 MODULE_DEVICE_TABLE(of, sdhci_dt_ids); 137 138 static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( 139 struct platform_device *pdev) 140 { 141 struct tegra_sdhci_platform_data *plat; 142 struct device_node *np = pdev->dev.of_node; 143 144 if (!np) 145 return NULL; 146 147 plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); 148 if (!plat) { 149 dev_err(&pdev->dev, "Can't allocate platform data\n"); 150 return NULL; 151 } 152 153 plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); 154 plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); 155 plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0); 156 if (of_find_property(np, "support-8bit", NULL)) 157 plat->is_8bit = 1; 158 159 return plat; 160 } 161 162 static int __devinit sdhci_tegra_probe(struct platform_device *pdev) 163 { 164 struct sdhci_pltfm_host *pltfm_host; 165 struct tegra_sdhci_platform_data *plat; 166 struct sdhci_host *host; 167 struct clk *clk; 168 int rc; 169 170 host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata); 171 if (IS_ERR(host)) 172 return PTR_ERR(host); 173 174 pltfm_host = sdhci_priv(host); 175 176 plat = pdev->dev.platform_data; 177 178 if (plat == NULL) 179 plat = sdhci_tegra_dt_parse_pdata(pdev); 180 181 if (plat == NULL) { 182 dev_err(mmc_dev(host->mmc), "missing platform data\n"); 183 rc = -ENXIO; 184 goto err_no_plat; 185 } 186 187 pltfm_host->priv = plat; 188 189 if (gpio_is_valid(plat->power_gpio)) { 190 rc = gpio_request(plat->power_gpio, "sdhci_power"); 191 if (rc) { 192 dev_err(mmc_dev(host->mmc), 193 "failed to allocate power gpio\n"); 194 goto err_power_req; 195 } 196 tegra_gpio_enable(plat->power_gpio); 197 gpio_direction_output(plat->power_gpio, 1); 198 } 199 200 if (gpio_is_valid(plat->cd_gpio)) { 201 rc = gpio_request(plat->cd_gpio, "sdhci_cd"); 202 if (rc) { 203 dev_err(mmc_dev(host->mmc), 204 "failed to allocate cd gpio\n"); 205 goto err_cd_req; 206 } 207 tegra_gpio_enable(plat->cd_gpio); 208 gpio_direction_input(plat->cd_gpio); 209 210 rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, 211 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 212 mmc_hostname(host->mmc), host); 213 214 if (rc) { 215 dev_err(mmc_dev(host->mmc), "request irq error\n"); 216 goto err_cd_irq_req; 217 } 218 219 } 220 221 if (gpio_is_valid(plat->wp_gpio)) { 222 rc = gpio_request(plat->wp_gpio, "sdhci_wp"); 223 if (rc) { 224 dev_err(mmc_dev(host->mmc), 225 "failed to allocate wp gpio\n"); 226 goto err_wp_req; 227 } 228 tegra_gpio_enable(plat->wp_gpio); 229 gpio_direction_input(plat->wp_gpio); 230 } 231 232 clk = clk_get(mmc_dev(host->mmc), NULL); 233 if (IS_ERR(clk)) { 234 dev_err(mmc_dev(host->mmc), "clk err\n"); 235 rc = PTR_ERR(clk); 236 goto err_clk_get; 237 } 238 clk_enable(clk); 239 pltfm_host->clk = clk; 240 241 host->mmc->pm_caps = plat->pm_flags; 242 243 if (plat->is_8bit) 244 host->mmc->caps |= MMC_CAP_8_BIT_DATA; 245 246 rc = sdhci_add_host(host); 247 if (rc) 248 goto err_add_host; 249 250 return 0; 251 252 err_add_host: 253 clk_disable(pltfm_host->clk); 254 clk_put(pltfm_host->clk); 255 err_clk_get: 256 if (gpio_is_valid(plat->wp_gpio)) { 257 tegra_gpio_disable(plat->wp_gpio); 258 gpio_free(plat->wp_gpio); 259 } 260 err_wp_req: 261 if (gpio_is_valid(plat->cd_gpio)) 262 free_irq(gpio_to_irq(plat->cd_gpio), host); 263 err_cd_irq_req: 264 if (gpio_is_valid(plat->cd_gpio)) { 265 tegra_gpio_disable(plat->cd_gpio); 266 gpio_free(plat->cd_gpio); 267 } 268 err_cd_req: 269 if (gpio_is_valid(plat->power_gpio)) { 270 tegra_gpio_disable(plat->power_gpio); 271 gpio_free(plat->power_gpio); 272 } 273 err_power_req: 274 err_no_plat: 275 sdhci_pltfm_free(pdev); 276 return rc; 277 } 278 279 static int __devexit sdhci_tegra_remove(struct platform_device *pdev) 280 { 281 struct sdhci_host *host = platform_get_drvdata(pdev); 282 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 283 struct tegra_sdhci_platform_data *plat = pltfm_host->priv; 284 int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 285 286 sdhci_remove_host(host, dead); 287 288 if (gpio_is_valid(plat->wp_gpio)) { 289 tegra_gpio_disable(plat->wp_gpio); 290 gpio_free(plat->wp_gpio); 291 } 292 293 if (gpio_is_valid(plat->cd_gpio)) { 294 free_irq(gpio_to_irq(plat->cd_gpio), host); 295 tegra_gpio_disable(plat->cd_gpio); 296 gpio_free(plat->cd_gpio); 297 } 298 299 if (gpio_is_valid(plat->power_gpio)) { 300 tegra_gpio_disable(plat->power_gpio); 301 gpio_free(plat->power_gpio); 302 } 303 304 clk_disable(pltfm_host->clk); 305 clk_put(pltfm_host->clk); 306 307 sdhci_pltfm_free(pdev); 308 309 return 0; 310 } 311 312 static struct platform_driver sdhci_tegra_driver = { 313 .driver = { 314 .name = "sdhci-tegra", 315 .owner = THIS_MODULE, 316 .of_match_table = sdhci_tegra_dt_match, 317 }, 318 .probe = sdhci_tegra_probe, 319 .remove = __devexit_p(sdhci_tegra_remove), 320 #ifdef CONFIG_PM 321 .suspend = sdhci_pltfm_suspend, 322 .resume = sdhci_pltfm_resume, 323 #endif 324 }; 325 326 static int __init sdhci_tegra_init(void) 327 { 328 return platform_driver_register(&sdhci_tegra_driver); 329 } 330 module_init(sdhci_tegra_init); 331 332 static void __exit sdhci_tegra_exit(void) 333 { 334 platform_driver_unregister(&sdhci_tegra_driver); 335 } 336 module_exit(sdhci_tegra_exit); 337 338 MODULE_DESCRIPTION("SDHCI driver for Tegra"); 339 MODULE_AUTHOR(" Google, Inc."); 340 MODULE_LICENSE("GPL v2"); 341