diff options
author | Anton Vorontsov <avorontsov@mvista.com> | 2010-08-10 21:01:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-11 11:59:03 -0400 |
commit | 20b1597bcf4a76ccab232fa032f5f9ad30069167 (patch) | |
tree | 37ff80d3df4d7d10a35276080f319bb340e4ea2b /drivers/mmc/host/sdhci-cns3xxx.c | |
parent | 845e3f4f06f9b1d34f39601cb6b7abfb8f40653c (diff) |
sdhci-pltfm: add support for CNS3xxx SoC devices
There's nothing special, just SoC-specific ops and quirks.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
Cc: Ben Dooks <ben@simtec.co.uk>
Cc: Richard R?jfors <richard.rojfors@pelagicore.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mmc/host/sdhci-cns3xxx.c')
-rw-r--r-- | drivers/mmc/host/sdhci-cns3xxx.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c new file mode 100644 index 000000000000..b7050b380d5f --- /dev/null +++ b/drivers/mmc/host/sdhci-cns3xxx.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * SDHCI support for CNS3xxx SoC | ||
3 | * | ||
4 | * Copyright 2008 Cavium Networks | ||
5 | * Copyright 2010 MontaVista Software, LLC. | ||
6 | * | ||
7 | * Authors: Scott Shu | ||
8 | * Anton Vorontsov <avorontsov@mvista.com> | ||
9 | * | ||
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. | ||
13 | */ | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/mmc/host.h> | ||
18 | #include <linux/sdhci-pltfm.h> | ||
19 | #include <mach/cns3xxx.h> | ||
20 | #include "sdhci.h" | ||
21 | #include "sdhci-pltfm.h" | ||
22 | |||
23 | static unsigned int sdhci_cns3xxx_get_max_clk(struct sdhci_host *host) | ||
24 | { | ||
25 | return 150000000; | ||
26 | } | ||
27 | |||
28 | static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock) | ||
29 | { | ||
30 | struct device *dev = mmc_dev(host->mmc); | ||
31 | int div = 1; | ||
32 | u16 clk; | ||
33 | unsigned long timeout; | ||
34 | |||
35 | if (clock == host->clock) | ||
36 | return; | ||
37 | |||
38 | sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); | ||
39 | |||
40 | if (clock == 0) | ||
41 | goto out; | ||
42 | |||
43 | while (host->max_clk / div > clock) { | ||
44 | /* | ||
45 | * On CNS3xxx divider grows linearly up to 4, and then | ||
46 | * exponentially up to 256. | ||
47 | */ | ||
48 | if (div < 4) | ||
49 | div += 1; | ||
50 | else if (div < 256) | ||
51 | div *= 2; | ||
52 | else | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | dev_dbg(dev, "desired SD clock: %d, actual: %d\n", | ||
57 | clock, host->max_clk / div); | ||
58 | |||
59 | /* Divide by 3 is special. */ | ||
60 | if (div != 3) | ||
61 | div >>= 1; | ||
62 | |||
63 | clk = div << SDHCI_DIVIDER_SHIFT; | ||
64 | clk |= SDHCI_CLOCK_INT_EN; | ||
65 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); | ||
66 | |||
67 | timeout = 20; | ||
68 | while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) | ||
69 | & SDHCI_CLOCK_INT_STABLE)) { | ||
70 | if (timeout == 0) { | ||
71 | dev_warn(dev, "clock is unstable"); | ||
72 | break; | ||
73 | } | ||
74 | timeout--; | ||
75 | mdelay(1); | ||
76 | } | ||
77 | |||
78 | clk |= SDHCI_CLOCK_CARD_EN; | ||
79 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); | ||
80 | out: | ||
81 | host->clock = clock; | ||
82 | } | ||
83 | |||
84 | static struct sdhci_ops sdhci_cns3xxx_ops = { | ||
85 | .get_max_clock = sdhci_cns3xxx_get_max_clk, | ||
86 | .set_clock = sdhci_cns3xxx_set_clock, | ||
87 | }; | ||
88 | |||
89 | struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { | ||
90 | .ops = &sdhci_cns3xxx_ops, | ||
91 | .quirks = SDHCI_QUIRK_BROKEN_DMA | | ||
92 | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | | ||
93 | SDHCI_QUIRK_INVERTED_WRITE_PROTECT | | ||
94 | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | | ||
95 | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | | ||
96 | SDHCI_QUIRK_NONSTANDARD_CLOCK, | ||
97 | }; | ||