diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 77 |
1 files changed, 38 insertions, 39 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c279fbc4c2e5..9d4fdfa685e5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/highmem.h> | 17 | #include <linux/highmem.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
20 | #include <linux/slab.h> | ||
20 | #include <linux/scatterlist.h> | 21 | #include <linux/scatterlist.h> |
21 | 22 | ||
22 | #include <linux/leds.h> | 23 | #include <linux/leds.h> |
@@ -174,20 +175,31 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) | |||
174 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); | 175 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); |
175 | } | 176 | } |
176 | 177 | ||
177 | static void sdhci_init(struct sdhci_host *host) | 178 | static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); |
179 | |||
180 | static void sdhci_init(struct sdhci_host *host, int soft) | ||
178 | { | 181 | { |
179 | sdhci_reset(host, SDHCI_RESET_ALL); | 182 | if (soft) |
183 | sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); | ||
184 | else | ||
185 | sdhci_reset(host, SDHCI_RESET_ALL); | ||
180 | 186 | ||
181 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, | 187 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, |
182 | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | | 188 | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | |
183 | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | | 189 | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | |
184 | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | | 190 | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | |
185 | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); | 191 | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); |
192 | |||
193 | if (soft) { | ||
194 | /* force clock reconfiguration */ | ||
195 | host->clock = 0; | ||
196 | sdhci_set_ios(host->mmc, &host->mmc->ios); | ||
197 | } | ||
186 | } | 198 | } |
187 | 199 | ||
188 | static void sdhci_reinit(struct sdhci_host *host) | 200 | static void sdhci_reinit(struct sdhci_host *host) |
189 | { | 201 | { |
190 | sdhci_init(host); | 202 | sdhci_init(host, 0); |
191 | sdhci_enable_card_detection(host); | 203 | sdhci_enable_card_detection(host); |
192 | } | 204 | } |
193 | 205 | ||
@@ -376,6 +388,20 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) | |||
376 | local_irq_restore(*flags); | 388 | local_irq_restore(*flags); |
377 | } | 389 | } |
378 | 390 | ||
391 | static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd) | ||
392 | { | ||
393 | __le32 *dataddr = (__le32 __force *)(desc + 4); | ||
394 | __le16 *cmdlen = (__le16 __force *)desc; | ||
395 | |||
396 | /* SDHCI specification says ADMA descriptors should be 4 byte | ||
397 | * aligned, so using 16 or 32bit operations should be safe. */ | ||
398 | |||
399 | cmdlen[0] = cpu_to_le16(cmd); | ||
400 | cmdlen[1] = cpu_to_le16(len); | ||
401 | |||
402 | dataddr[0] = cpu_to_le32(addr); | ||
403 | } | ||
404 | |||
379 | static int sdhci_adma_table_pre(struct sdhci_host *host, | 405 | static int sdhci_adma_table_pre(struct sdhci_host *host, |
380 | struct mmc_data *data) | 406 | struct mmc_data *data) |
381 | { | 407 | { |
@@ -443,19 +469,11 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, | |||
443 | sdhci_kunmap_atomic(buffer, &flags); | 469 | sdhci_kunmap_atomic(buffer, &flags); |
444 | } | 470 | } |
445 | 471 | ||
446 | desc[7] = (align_addr >> 24) & 0xff; | 472 | /* tran, valid */ |
447 | desc[6] = (align_addr >> 16) & 0xff; | 473 | sdhci_set_adma_desc(desc, align_addr, offset, 0x21); |
448 | desc[5] = (align_addr >> 8) & 0xff; | ||
449 | desc[4] = (align_addr >> 0) & 0xff; | ||
450 | 474 | ||
451 | BUG_ON(offset > 65536); | 475 | BUG_ON(offset > 65536); |
452 | 476 | ||
453 | desc[3] = (offset >> 8) & 0xff; | ||
454 | desc[2] = (offset >> 0) & 0xff; | ||
455 | |||
456 | desc[1] = 0x00; | ||
457 | desc[0] = 0x21; /* tran, valid */ | ||
458 | |||
459 | align += 4; | 477 | align += 4; |
460 | align_addr += 4; | 478 | align_addr += 4; |
461 | 479 | ||
@@ -465,19 +483,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, | |||
465 | len -= offset; | 483 | len -= offset; |
466 | } | 484 | } |
467 | 485 | ||
468 | desc[7] = (addr >> 24) & 0xff; | ||
469 | desc[6] = (addr >> 16) & 0xff; | ||
470 | desc[5] = (addr >> 8) & 0xff; | ||
471 | desc[4] = (addr >> 0) & 0xff; | ||
472 | |||
473 | BUG_ON(len > 65536); | 486 | BUG_ON(len > 65536); |
474 | 487 | ||
475 | desc[3] = (len >> 8) & 0xff; | 488 | /* tran, valid */ |
476 | desc[2] = (len >> 0) & 0xff; | 489 | sdhci_set_adma_desc(desc, addr, len, 0x21); |
477 | |||
478 | desc[1] = 0x00; | ||
479 | desc[0] = 0x21; /* tran, valid */ | ||
480 | |||
481 | desc += 8; | 490 | desc += 8; |
482 | 491 | ||
483 | /* | 492 | /* |
@@ -490,16 +499,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, | |||
490 | /* | 499 | /* |
491 | * Add a terminating entry. | 500 | * Add a terminating entry. |
492 | */ | 501 | */ |
493 | desc[7] = 0; | ||
494 | desc[6] = 0; | ||
495 | desc[5] = 0; | ||
496 | desc[4] = 0; | ||
497 | 502 | ||
498 | desc[3] = 0; | 503 | /* nop, end, valid */ |
499 | desc[2] = 0; | 504 | sdhci_set_adma_desc(desc, 0, 0, 0x3); |
500 | |||
501 | desc[1] = 0x00; | ||
502 | desc[0] = 0x03; /* nop, end, valid */ | ||
503 | 505 | ||
504 | /* | 506 | /* |
505 | * Resync align buffer as we might have changed it. | 507 | * Resync align buffer as we might have changed it. |
@@ -1610,16 +1612,13 @@ int sdhci_resume_host(struct sdhci_host *host) | |||
1610 | if (ret) | 1612 | if (ret) |
1611 | return ret; | 1613 | return ret; |
1612 | 1614 | ||
1613 | sdhci_init(host); | 1615 | sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); |
1614 | mmiowb(); | 1616 | mmiowb(); |
1615 | 1617 | ||
1616 | ret = mmc_resume_host(host->mmc); | 1618 | ret = mmc_resume_host(host->mmc); |
1617 | if (ret) | ||
1618 | return ret; | ||
1619 | |||
1620 | sdhci_enable_card_detection(host); | 1619 | sdhci_enable_card_detection(host); |
1621 | 1620 | ||
1622 | return 0; | 1621 | return ret; |
1623 | } | 1622 | } |
1624 | 1623 | ||
1625 | EXPORT_SYMBOL_GPL(sdhci_resume_host); | 1624 | EXPORT_SYMBOL_GPL(sdhci_resume_host); |
@@ -1874,7 +1873,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
1874 | if (ret) | 1873 | if (ret) |
1875 | goto untasklet; | 1874 | goto untasklet; |
1876 | 1875 | ||
1877 | sdhci_init(host); | 1876 | sdhci_init(host, 0); |
1878 | 1877 | ||
1879 | #ifdef CONFIG_MMC_DEBUG | 1878 | #ifdef CONFIG_MMC_DEBUG |
1880 | sdhci_dumpregs(host); | 1879 | sdhci_dumpregs(host); |