diff options
-rw-r--r-- | drivers/mmc/host/Kconfig | 9 | ||||
-rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-cns3xxx.c | 97 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pltfm.c | 3 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pltfm.h | 4 |
5 files changed, 114 insertions, 0 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d25e22cee4c4..c997474c649f 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
@@ -121,6 +121,15 @@ config MMC_SDHCI_PLTFM | |||
121 | 121 | ||
122 | If unsure, say N. | 122 | If unsure, say N. |
123 | 123 | ||
124 | config MMC_SDHCI_CNS3XXX | ||
125 | bool "SDHCI support on the Cavium Networks CNS3xxx SoC" | ||
126 | depends on ARCH_CNS3XXX | ||
127 | depends on MMC_SDHCI_PLTFM | ||
128 | help | ||
129 | This selects the SDHCI support for CNS3xxx System-on-Chip devices. | ||
130 | |||
131 | If unsure, say N. | ||
132 | |||
124 | config MMC_SDHCI_S3C | 133 | config MMC_SDHCI_S3C |
125 | tristate "SDHCI support on Samsung S3C SoC" | 134 | tristate "SDHCI support on Samsung S3C SoC" |
126 | depends on MMC_SDHCI && (PLAT_S3C24XX || PLAT_S3C64XX) | 135 | depends on MMC_SDHCI && (PLAT_S3C24XX || PLAT_S3C64XX) |
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index c6955d7b0eca..fe0ba4e2b8b0 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
@@ -39,6 +39,7 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o | |||
39 | 39 | ||
40 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o | 40 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o |
41 | sdhci-platform-y := sdhci-pltfm.o | 41 | sdhci-platform-y := sdhci-pltfm.o |
42 | sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o | ||
42 | 43 | ||
43 | obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o | 44 | obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o |
44 | sdhci-of-y := sdhci-of-core.o | 45 | sdhci-of-y := sdhci-of-core.o |
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 | }; | ||
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 4c043bb9ff12..e045e3c61dde 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c | |||
@@ -158,6 +158,9 @@ static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) | |||
158 | 158 | ||
159 | static const struct platform_device_id sdhci_pltfm_ids[] = { | 159 | static const struct platform_device_id sdhci_pltfm_ids[] = { |
160 | { "sdhci", }, | 160 | { "sdhci", }, |
161 | #ifdef CONFIG_MMC_SDHCI_CNS3XXX | ||
162 | { "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata }, | ||
163 | #endif | ||
161 | { }, | 164 | { }, |
162 | }; | 165 | }; |
163 | MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids); | 166 | MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids); |
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 4aa07a918b62..900f32902f73 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h | |||
@@ -11,4 +11,8 @@ | |||
11 | #ifndef _DRIVERS_MMC_SDHCI_PLTFM_H | 11 | #ifndef _DRIVERS_MMC_SDHCI_PLTFM_H |
12 | #define _DRIVERS_MMC_SDHCI_PLTFM_H | 12 | #define _DRIVERS_MMC_SDHCI_PLTFM_H |
13 | 13 | ||
14 | #include <linux/sdhci-pltfm.h> | ||
15 | |||
16 | extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; | ||
17 | |||
14 | #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ | 18 | #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ |