1 /* linux/drivers/mmc/host/sdhci-pxa.c
3 * Copyright (C) 2010 Marvell International Ltd.
4 * Zhangfei Gao <zhangfei.gao@marvell.com>
5 * Kevin Wang <dwang4@marvell.com>
6 * Mingwei Wang <mwwang@marvell.com>
7 * Philip Rakity <prakity@marvell.com>
8 * Mark Brown <markb@marvell.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
16 * SDHCI support for MMP2/PXA910/PXA168
18 * Refer to sdhci-s3c.c.
21 #include <linux/delay.h>
22 #include <linux/platform_device.h>
23 #include <linux/mmc/host.h>
24 #include <linux/clk.h>
26 #include <linux/err.h>
27 #include <plat/sdhci.h>
30 #define DRIVER_NAME "sdhci-pxa"
32 #define SD_FIFO_PARAM 0x104
33 #define DIS_PAD_SD_CLK_GATE 0x400
36 struct sdhci_host
*host
;
37 struct sdhci_pxa_platdata
*pdata
;
44 /*****************************************************************************\
46 * SDHCI core callbacks *
48 \*****************************************************************************/
49 static void set_clock(struct sdhci_host
*host
, unsigned int clock
)
51 struct sdhci_pxa
*pxa
= sdhci_priv(host
);
55 if (pxa
->clk_enable
) {
56 clk_disable(pxa
->clk
);
60 if (0 == pxa
->clk_enable
) {
61 if (pxa
->pdata
->flags
& PXA_FLAG_DISABLE_CLOCK_GATING
) {
62 tmp
= readl(host
->ioaddr
+ SD_FIFO_PARAM
);
63 tmp
|= DIS_PAD_SD_CLK_GATE
;
64 writel(tmp
, host
->ioaddr
+ SD_FIFO_PARAM
);
72 static struct sdhci_ops sdhci_pxa_ops
= {
73 .set_clock
= set_clock
,
76 /*****************************************************************************\
78 * Device probing/removal *
80 \*****************************************************************************/
82 static int __devinit
sdhci_pxa_probe(struct platform_device
*pdev
)
84 struct sdhci_pxa_platdata
*pdata
= pdev
->dev
.platform_data
;
85 struct device
*dev
= &pdev
->dev
;
86 struct sdhci_host
*host
= NULL
;
87 struct resource
*iomem
= NULL
;
88 struct sdhci_pxa
*pxa
= NULL
;
91 irq
= platform_get_irq(pdev
, 0);
93 dev_err(dev
, "no irq specified\n");
97 iomem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
99 dev_err(dev
, "no memory specified\n");
103 host
= sdhci_alloc_host(&pdev
->dev
, sizeof(struct sdhci_pxa
));
105 dev_err(dev
, "failed to alloc host\n");
106 return PTR_ERR(host
);
109 pxa
= sdhci_priv(host
);
114 pxa
->clk
= clk_get(dev
, "PXA-SDHCLK");
115 if (IS_ERR(pxa
->clk
)) {
116 dev_err(dev
, "failed to get io clock\n");
117 ret
= PTR_ERR(pxa
->clk
);
121 pxa
->res
= request_mem_region(iomem
->start
, resource_size(iomem
),
122 mmc_hostname(host
->mmc
));
124 dev_err(&pdev
->dev
, "cannot request region\n");
129 host
->ioaddr
= ioremap(iomem
->start
, resource_size(iomem
));
131 dev_err(&pdev
->dev
, "failed to remap registers\n");
136 host
->hw_name
= "MMC";
137 host
->ops
= &sdhci_pxa_ops
;
139 host
->quirks
= SDHCI_QUIRK_BROKEN_ADMA
| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
;
142 host
->quirks
|= pdata
->quirks
;
144 ret
= sdhci_add_host(host
);
146 dev_err(&pdev
->dev
, "failed to add host\n");
150 if (pxa
->pdata
->max_speed
)
151 host
->mmc
->f_max
= pxa
->pdata
->max_speed
;
153 platform_set_drvdata(pdev
, host
);
160 iounmap(host
->ioaddr
);
162 release_mem_region(pxa
->res
->start
,
163 resource_size(pxa
->res
));
164 sdhci_free_host(host
);
170 static int __devexit
sdhci_pxa_remove(struct platform_device
*pdev
)
172 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
173 struct sdhci_pxa
*pxa
= sdhci_priv(host
);
178 scratch
= readl(host
->ioaddr
+ SDHCI_INT_STATUS
);
179 if (scratch
== (u32
)-1)
182 sdhci_remove_host(host
, dead
);
185 iounmap(host
->ioaddr
);
187 release_mem_region(pxa
->res
->start
,
188 resource_size(pxa
->res
));
189 if (pxa
->clk_enable
) {
190 clk_disable(pxa
->clk
);
195 sdhci_free_host(host
);
196 platform_set_drvdata(pdev
, NULL
);
203 static int sdhci_pxa_suspend(struct platform_device
*dev
, pm_message_t state
)
205 struct sdhci_host
*host
= platform_get_drvdata(dev
);
207 return sdhci_suspend_host(host
, state
);
210 static int sdhci_pxa_resume(struct platform_device
*dev
)
212 struct sdhci_host
*host
= platform_get_drvdata(dev
);
214 return sdhci_resume_host(host
);
217 #define sdhci_pxa_suspend NULL
218 #define sdhci_pxa_resume NULL
221 static struct platform_driver sdhci_pxa_driver
= {
222 .probe
= sdhci_pxa_probe
,
223 .remove
= __devexit_p(sdhci_pxa_remove
),
224 .suspend
= sdhci_pxa_suspend
,
225 .resume
= sdhci_pxa_resume
,
228 .owner
= THIS_MODULE
,
232 /*****************************************************************************\
236 \*****************************************************************************/
238 static int __init
sdhci_pxa_init(void)
240 return platform_driver_register(&sdhci_pxa_driver
);
243 static void __exit
sdhci_pxa_exit(void)
245 platform_driver_unregister(&sdhci_pxa_driver
);
248 module_init(sdhci_pxa_init
);
249 module_exit(sdhci_pxa_exit
);
251 MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2");
252 MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
253 MODULE_LICENSE("GPL v2");