2 * OpenFirmware bindings for Secure Digital Host Controller Interface.
4 * Copyright (c) 2007 Freescale Semiconductor, Inc.
5 * Copyright (c) 2009 MontaVista Software, Inc.
7 * Authors: Xiaobo Xie <X.Xie@freescale.com>
8 * Anton Vorontsov <avorontsov@ru.mvista.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 as published by
12 * the Free Software Foundation; either version 2 of the License, or (at
13 * your option) any later version.
16 #include <linux/module.h>
17 #include <linux/init.h>
19 #include <linux/interrupt.h>
20 #include <linux/delay.h>
22 #include <linux/of_platform.h>
23 #include <linux/mmc/host.h>
26 struct sdhci_of_data
{
31 struct sdhci_of_host
{
37 * Ops and quirks for the Freescale eSDHC controller.
40 #define ESDHC_DMA_SYSCTL 0x40c
41 #define ESDHC_DMA_SNOOP 0x00000040
43 #define ESDHC_SYSTEM_CONTROL 0x2c
44 #define ESDHC_CLOCK_MASK 0x0000fff0
45 #define ESDHC_PREDIV_SHIFT 8
46 #define ESDHC_DIVIDER_SHIFT 4
47 #define ESDHC_CLOCK_PEREN 0x00000004
48 #define ESDHC_CLOCK_HCKEN 0x00000002
49 #define ESDHC_CLOCK_IPGEN 0x00000001
51 static u32
esdhc_readl(struct sdhci_host
*host
, int reg
)
53 return in_be32(host
->ioaddr
+ reg
);
56 static u16
esdhc_readw(struct sdhci_host
*host
, int reg
)
60 if (unlikely(reg
== SDHCI_HOST_VERSION
))
61 ret
= in_be16(host
->ioaddr
+ reg
);
63 ret
= in_be16(host
->ioaddr
+ (reg
^ 0x2));
67 static u8
esdhc_readb(struct sdhci_host
*host
, int reg
)
69 return in_8(host
->ioaddr
+ (reg
^ 0x3));
72 static void esdhc_writel(struct sdhci_host
*host
, u32 val
, int reg
)
74 out_be32(host
->ioaddr
+ reg
, val
);
77 static void esdhc_writew(struct sdhci_host
*host
, u16 val
, int reg
)
79 struct sdhci_of_host
*of_host
= sdhci_priv(host
);
80 int base
= reg
& ~0x3;
81 int shift
= (reg
& 0x2) * 8;
84 case SDHCI_TRANSFER_MODE
:
86 * Postpone this write, we must do it together with a
87 * command write that is down below.
89 of_host
->xfer_mode_shadow
= val
;
92 esdhc_writel(host
, val
<< 16 | of_host
->xfer_mode_shadow
,
95 case SDHCI_BLOCK_SIZE
:
97 * Two last DMA bits are reserved, and first one is used for
98 * non-standard blksz of 4096 bytes that we don't support
99 * yet. So clear the DMA boundary bits.
101 val
&= ~SDHCI_MAKE_BLKSZ(0x7, 0);
104 clrsetbits_be32(host
->ioaddr
+ base
, 0xffff << shift
, val
<< shift
);
107 static void esdhc_writeb(struct sdhci_host
*host
, u8 val
, int reg
)
109 int base
= reg
& ~0x3;
110 int shift
= (reg
& 0x3) * 8;
112 clrsetbits_be32(host
->ioaddr
+ base
, 0xff << shift
, val
<< shift
);
115 static void esdhc_set_clock(struct sdhci_host
*host
, unsigned int clock
)
120 clrbits32(host
->ioaddr
+ ESDHC_SYSTEM_CONTROL
, ESDHC_CLOCK_IPGEN
|
121 ESDHC_CLOCK_HCKEN
| ESDHC_CLOCK_PEREN
| ESDHC_CLOCK_MASK
);
126 if (host
->max_clk
/ 16 > clock
) {
127 for (; pre_div
< 256; pre_div
*= 2) {
128 if (host
->max_clk
/ pre_div
< clock
* 16)
133 for (div
= 1; div
<= 16; div
++) {
134 if (host
->max_clk
/ (div
* pre_div
) <= clock
)
140 setbits32(host
->ioaddr
+ ESDHC_SYSTEM_CONTROL
, ESDHC_CLOCK_IPGEN
|
141 ESDHC_CLOCK_HCKEN
| ESDHC_CLOCK_PEREN
|
142 div
<< ESDHC_DIVIDER_SHIFT
| pre_div
<< ESDHC_PREDIV_SHIFT
);
148 static int esdhc_enable_dma(struct sdhci_host
*host
)
150 setbits32(host
->ioaddr
+ ESDHC_DMA_SYSCTL
, ESDHC_DMA_SNOOP
);
154 static unsigned int esdhc_get_max_clock(struct sdhci_host
*host
)
156 struct sdhci_of_host
*of_host
= sdhci_priv(host
);
158 return of_host
->clock
;
161 static unsigned int esdhc_get_min_clock(struct sdhci_host
*host
)
163 struct sdhci_of_host
*of_host
= sdhci_priv(host
);
165 return of_host
->clock
/ 256 / 16;
168 static unsigned int esdhc_get_timeout_clock(struct sdhci_host
*host
)
170 struct sdhci_of_host
*of_host
= sdhci_priv(host
);
172 return of_host
->clock
/ 1000;
175 static struct sdhci_of_data sdhci_esdhc
= {
176 .quirks
= SDHCI_QUIRK_FORCE_BLK_SZ_2048
|
177 SDHCI_QUIRK_BROKEN_CARD_DETECTION
|
178 SDHCI_QUIRK_INVERTED_WRITE_PROTECT
|
179 SDHCI_QUIRK_NO_BUSY_IRQ
|
180 SDHCI_QUIRK_NONSTANDARD_CLOCK
|
181 SDHCI_QUIRK_PIO_NEEDS_DELAY
|
182 SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET
|
183 SDHCI_QUIRK_NO_CARD_NO_RESET
,
185 .readl
= esdhc_readl
,
186 .readw
= esdhc_readw
,
187 .readb
= esdhc_readb
,
188 .writel
= esdhc_writel
,
189 .writew
= esdhc_writew
,
190 .writeb
= esdhc_writeb
,
191 .set_clock
= esdhc_set_clock
,
192 .enable_dma
= esdhc_enable_dma
,
193 .get_max_clock
= esdhc_get_max_clock
,
194 .get_min_clock
= esdhc_get_min_clock
,
195 .get_timeout_clock
= esdhc_get_timeout_clock
,
201 static int sdhci_of_suspend(struct of_device
*ofdev
, pm_message_t state
)
203 struct sdhci_host
*host
= dev_get_drvdata(&ofdev
->dev
);
205 return mmc_suspend_host(host
->mmc
, state
);
208 static int sdhci_of_resume(struct of_device
*ofdev
)
210 struct sdhci_host
*host
= dev_get_drvdata(&ofdev
->dev
);
212 return mmc_resume_host(host
->mmc
);
217 #define sdhci_of_suspend NULL
218 #define sdhci_of_resume NULL
222 static int __devinit
sdhci_of_probe(struct of_device
*ofdev
,
223 const struct of_device_id
*match
)
225 struct device_node
*np
= ofdev
->node
;
226 struct sdhci_of_data
*sdhci_of_data
= match
->data
;
227 struct sdhci_host
*host
;
228 struct sdhci_of_host
*of_host
;
233 if (!of_device_is_available(np
))
236 host
= sdhci_alloc_host(&ofdev
->dev
, sizeof(*of_host
));
240 of_host
= sdhci_priv(host
);
241 dev_set_drvdata(&ofdev
->dev
, host
);
243 host
->ioaddr
= of_iomap(np
, 0);
249 host
->irq
= irq_of_parse_and_map(np
, 0);
255 host
->hw_name
= dev_name(&ofdev
->dev
);
257 host
->quirks
= sdhci_of_data
->quirks
;
258 host
->ops
= &sdhci_of_data
->ops
;
261 if (of_get_property(np
, "sdhci,1-bit-only", NULL
))
262 host
->quirks
|= SDHCI_QUIRK_FORCE_1_BIT_DATA
;
264 clk
= of_get_property(np
, "clock-frequency", &size
);
265 if (clk
&& size
== sizeof(*clk
) && *clk
)
266 of_host
->clock
= *clk
;
268 ret
= sdhci_add_host(host
);
275 irq_dispose_mapping(host
->irq
);
277 iounmap(host
->ioaddr
);
279 sdhci_free_host(host
);
283 static int __devexit
sdhci_of_remove(struct of_device
*ofdev
)
285 struct sdhci_host
*host
= dev_get_drvdata(&ofdev
->dev
);
287 sdhci_remove_host(host
, 0);
288 sdhci_free_host(host
);
289 irq_dispose_mapping(host
->irq
);
290 iounmap(host
->ioaddr
);
294 static const struct of_device_id sdhci_of_match
[] = {
295 { .compatible
= "fsl,mpc8379-esdhc", .data
= &sdhci_esdhc
, },
296 { .compatible
= "fsl,mpc8536-esdhc", .data
= &sdhci_esdhc
, },
297 { .compatible
= "fsl,esdhc", .data
= &sdhci_esdhc
, },
298 { .compatible
= "generic-sdhci", },
301 MODULE_DEVICE_TABLE(of
, sdhci_of_match
);
303 static struct of_platform_driver sdhci_of_driver
= {
304 .driver
.name
= "sdhci-of",
305 .match_table
= sdhci_of_match
,
306 .probe
= sdhci_of_probe
,
307 .remove
= __devexit_p(sdhci_of_remove
),
308 .suspend
= sdhci_of_suspend
,
309 .resume
= sdhci_of_resume
,
312 static int __init
sdhci_of_init(void)
314 return of_register_platform_driver(&sdhci_of_driver
);
316 module_init(sdhci_of_init
);
318 static void __exit
sdhci_of_exit(void)
320 of_unregister_platform_driver(&sdhci_of_driver
);
322 module_exit(sdhci_of_exit
);
324 MODULE_DESCRIPTION("Secure Digital Host Controller Interface OF driver");
325 MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
326 "Anton Vorontsov <avorontsov@ru.mvista.com>");
327 MODULE_LICENSE("GPL");