2 * drivers/mmc/host/sdhci-tegra.c
4 * Copyright (C) 2009 Palm, Inc.
5 * Author: Yvonne Yip <y@palm.com>
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/err.h>
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/clk.h>
24 #include <linux/gpio.h>
25 #include <linux/mmc/card.h>
27 #include <mach/sdhci.h>
31 #define DRIVER_NAME "sdhci-tegra"
33 struct tegra_sdhci_host {
34 struct sdhci_host *sdhci;
38 static irqreturn_t carddetect_irq(int irq, void *data)
40 struct sdhci_host *sdhost = (struct sdhci_host *)data;
42 sdhci_card_detect_callback(sdhost);
46 static int tegra_sdhci_enable_dma(struct sdhci_host *host)
51 static struct sdhci_ops tegra_sdhci_ops = {
52 .enable_dma = tegra_sdhci_enable_dma,
55 static int __devinit tegra_sdhci_probe(struct platform_device *pdev)
58 struct tegra_sdhci_platform_data *plat;
59 struct sdhci_host *sdhci;
60 struct tegra_sdhci_host *host;
65 plat = pdev->dev.platform_data;
69 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
75 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
79 ioaddr = ioremap(res->start, res->end - res->start);
81 sdhci = sdhci_alloc_host(&pdev->dev, sizeof(struct tegra_sdhci_host));
87 host = sdhci_priv(sdhci);
90 host->clk = clk_get(&pdev->dev, plat->clk_id);
91 if (IS_ERR(host->clk)) {
92 rc = PTR_ERR(host->clk);
96 rc = clk_enable(host->clk);
100 sdhci->hw_name = "tegra";
101 sdhci->ops = &tegra_sdhci_ops;
103 sdhci->ioaddr = ioaddr;
104 sdhci->version = SDHCI_SPEC_200;
105 sdhci->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
106 SDHCI_QUIRK_SINGLE_POWER_WRITE |
107 SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP |
108 SDHCI_QUIRK_BROKEN_WRITE_PROTECT |
109 SDHCI_QUIRK_BROKEN_CTRL_HISPD |
110 SDHCI_QUIRK_NO_HISPD_BIT |
111 SDHCI_QUIRK_8_BIT_DATA |
112 SDHCI_QUIRK_NO_VERSION_REG |
113 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
114 SDHCI_QUIRK_NO_SDIO_IRQ;
116 if (plat->force_hs != 0)
117 sdhci->quirks |= SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE;
119 rc = sdhci_add_host(sdhci);
121 goto err_clk_disable;
123 platform_set_drvdata(pdev, host);
125 if (plat->cd_gpio != -1) {
126 rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
127 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
128 mmc_hostname(sdhci->mmc), sdhci);
131 goto err_remove_host;
134 if (plat->board_probe)
135 plat->board_probe(pdev->id, sdhci->mmc);
137 printk(KERN_INFO "sdhci%d: initialized irq %d ioaddr %p\n", pdev->id,
138 sdhci->irq, sdhci->ioaddr);
143 sdhci_remove_host(sdhci, 1);
145 clk_disable(host->clk);
150 sdhci_free_host(sdhci);
152 iounmap(sdhci->ioaddr);
157 static int tegra_sdhci_remove(struct platform_device *pdev)
159 struct tegra_sdhci_host *host = platform_get_drvdata(pdev);
161 struct tegra_sdhci_platform_data *plat;
162 plat = pdev->dev.platform_data;
163 if (plat && plat->board_probe)
164 plat->board_probe(pdev->id, host->sdhci->mmc);
166 sdhci_remove_host(host->sdhci, 0);
167 sdhci_free_host(host->sdhci);
173 static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state)
175 struct tegra_sdhci_host *host = platform_get_drvdata(pdev);
178 ret = sdhci_suspend_host(host->sdhci, state);
180 pr_err("%s: failed, error = %d\n", __func__, ret);
185 static int tegra_sdhci_resume(struct platform_device *pdev)
187 struct tegra_sdhci_host *host = platform_get_drvdata(pdev);
190 ret = sdhci_resume_host(host->sdhci);
192 pr_err("%s: failed, error = %d\n", __func__, ret);
197 #define tegra_sdhci_suspend NULL
198 #define tegra_sdhci_resume NULL
201 static struct platform_driver tegra_sdhci_driver = {
202 .probe = tegra_sdhci_probe,
203 .remove = tegra_sdhci_remove,
204 .suspend = tegra_sdhci_suspend,
205 .resume = tegra_sdhci_resume,
208 .owner = THIS_MODULE,
212 static int __init tegra_sdhci_init(void)
214 return platform_driver_register(&tegra_sdhci_driver);
217 static void __exit tegra_sdhci_exit(void)
219 platform_driver_unregister(&tegra_sdhci_driver);
222 module_init(tegra_sdhci_init);
223 module_exit(tegra_sdhci_exit);
225 MODULE_DESCRIPTION("Tegra SDHCI controller driver");
226 MODULE_LICENSE("GPL");