diff options
-rw-r--r-- | drivers/mmc/host/mmci.c | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 0814b88b44d6..f67fd4f2ab48 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
@@ -51,6 +51,7 @@ static unsigned int fmax = 515633; | |||
51 | * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when | 51 | * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when |
52 | * using DMA. | 52 | * using DMA. |
53 | * @sdio: variant supports SDIO | 53 | * @sdio: variant supports SDIO |
54 | * @st_clkdiv: true if using a ST-specific clock divider algorithm | ||
54 | */ | 55 | */ |
55 | struct variant_data { | 56 | struct variant_data { |
56 | unsigned int clkreg; | 57 | unsigned int clkreg; |
@@ -61,6 +62,7 @@ struct variant_data { | |||
61 | bool broken_blockend; | 62 | bool broken_blockend; |
62 | bool broken_blockend_dma; | 63 | bool broken_blockend_dma; |
63 | bool sdio; | 64 | bool sdio; |
65 | bool st_clkdiv; | ||
64 | }; | 66 | }; |
65 | 67 | ||
66 | static struct variant_data variant_arm = { | 68 | static struct variant_data variant_arm = { |
@@ -86,7 +88,9 @@ static struct variant_data variant_ux500 = { | |||
86 | .datalength_bits = 24, | 88 | .datalength_bits = 24, |
87 | .broken_blockend = true, | 89 | .broken_blockend = true, |
88 | .sdio = true, | 90 | .sdio = true, |
91 | .st_clkdiv = true, | ||
89 | }; | 92 | }; |
93 | |||
90 | /* | 94 | /* |
91 | * This must be called with host->lock held | 95 | * This must be called with host->lock held |
92 | */ | 96 | */ |
@@ -97,9 +101,30 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) | |||
97 | 101 | ||
98 | if (desired) { | 102 | if (desired) { |
99 | if (desired >= host->mclk) { | 103 | if (desired >= host->mclk) { |
100 | clk = MCI_CLK_BYPASS; | 104 | /* |
105 | * The ST clock divider does not like the bypass bit, | ||
106 | * even though it's available. Instead the datasheet | ||
107 | * recommends setting the divider to zero. | ||
108 | */ | ||
109 | if (!variant->st_clkdiv) | ||
110 | clk = MCI_CLK_BYPASS; | ||
101 | host->cclk = host->mclk; | 111 | host->cclk = host->mclk; |
112 | } else if (variant->st_clkdiv) { | ||
113 | /* | ||
114 | * DB8500 TRM says f = mclk / (clkdiv + 2) | ||
115 | * => clkdiv = (mclk / f) - 2 | ||
116 | * Round the divider up so we don't exceed the max | ||
117 | * frequency | ||
118 | */ | ||
119 | clk = DIV_ROUND_UP(host->mclk, desired) - 2; | ||
120 | if (clk >= 256) | ||
121 | clk = 255; | ||
122 | host->cclk = host->mclk / (clk + 2); | ||
102 | } else { | 123 | } else { |
124 | /* | ||
125 | * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) | ||
126 | * => clkdiv = mclk / (2 * f) - 1 | ||
127 | */ | ||
103 | clk = host->mclk / (2 * desired) - 1; | 128 | clk = host->mclk / (2 * desired) - 1; |
104 | if (clk >= 256) | 129 | if (clk >= 256) |
105 | clk = 255; | 130 | clk = 255; |