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