diff options
Diffstat (limited to 'drivers/mmc/core/mmc.c')
-rw-r--r-- | drivers/mmc/core/mmc.c | 160 |
1 files changed, 107 insertions, 53 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 66f85bfa8dbb..65fe28860f54 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1,5 +1,5 @@ /* - * linux/drivers/mmc/mmc.c + * linux/drivers/mmc/core/mmc.c * * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. @@ -100,7 +100,7 @@ static int mmc_decode_cid(struct mmc_card *card) break; default: - printk("%s: card has unknown MMCA version %d\n", + printk(KERN_ERR "%s: card has unknown MMCA version %d\n", mmc_hostname(card->host), card->csd.mmca_vsn); return -EINVAL; } @@ -123,7 +123,7 @@ static int mmc_decode_csd(struct mmc_card *card) */ csd_struct = UNSTUFF_BITS(resp, 126, 2); if (csd_struct != 1 && csd_struct != 2) { - printk("%s: unrecognised CSD structure version %d\n", + printk(KERN_ERR "%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd_struct); return -EINVAL; } @@ -161,13 +161,12 @@ static int mmc_read_ext_csd(struct mmc_card *card) { int err; u8 *ext_csd; + unsigned int ext_csd_struct; BUG_ON(!card); - err = MMC_ERR_FAILED; - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return MMC_ERR_NONE; + return 0; /* * As the ext_csd is so large and mostly unused, we don't store the @@ -176,13 +175,19 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd = kmalloc(512, GFP_KERNEL); if (!ext_csd) { printk(KERN_ERR "%s: could not allocate a buffer to " - "receive the ext_csd. mmc v4 cards will be " - "treated as v3.\n", mmc_hostname(card->host)); - return MMC_ERR_FAILED; + "receive the ext_csd.\n", mmc_hostname(card->host)); + return -ENOMEM; } err = mmc_send_ext_csd(card, ext_csd); - if (err != MMC_ERR_NONE) { + if (err) { + /* + * We all hosts that cannot perform the command + * to fail more gracefully + */ + if (err != -EINVAL) + goto out; + /* * High capacity cards should have this "magic" size * stored in their CSD. @@ -197,18 +202,29 @@ static int mmc_read_ext_csd(struct mmc_card *card) "EXT_CSD, performance might " "suffer.\n", mmc_hostname(card->host)); - err = MMC_ERR_NONE; + err = 0; } + goto out; } - card->ext_csd.sectors = - ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | - ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | - ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | - ext_csd[EXT_CSD_SEC_CNT + 3] << 24; - if (card->ext_csd.sectors) - mmc_card_set_blockaddr(card); + ext_csd_struct = ext_csd[EXT_CSD_REV]; + if (ext_csd_struct > 2) { + printk(KERN_ERR "%s: unrecognised EXT_CSD structure " + "version %d\n", mmc_hostname(card->host), + ext_csd_struct); + return -EINVAL; + } + + if (ext_csd_struct >= 2) { + card->ext_csd.sectors = + ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | + ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | + ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | + ext_csd[EXT_CSD_SEC_CNT + 3] << 24; + if (card->ext_csd.sectors) + mmc_card_set_blockaddr(card); + } switch (ext_csd[EXT_CSD_CARD_TYPE]) { case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: @@ -246,7 +262,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, unsigned int max_dtr; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); /* * Since we're changing the OCR value, we seem to @@ -258,19 +274,33 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* The extra bit indicates that we support high capacity */ err = mmc_send_op_cond(host, ocr | (1 << 30), NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); - if (err != MMC_ERR_NONE) + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); + if (err) goto err; if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) + if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + err = -ENOENT; goto err; + } card = oldcard; } else { @@ -278,8 +308,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Allocate card structure. */ card = mmc_alloc_card(host); - if (IS_ERR(card)) + if (IS_ERR(card)) { + err = PTR_ERR(card); goto err; + } card->type = MMC_TYPE_MMC; card->rca = 1; @@ -287,43 +319,47 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* - * Set card RCA. + * For native busses: set card RCA and quit open drain mode. */ - err = mmc_set_relative_addr(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_set_relative_addr(card); + if (err) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* * Fetch CSD from card. */ err = mmc_send_csd(card, card->raw_csd); - if (err != MMC_ERR_NONE) + if (err) goto free_card; err = mmc_decode_csd(card); - if (err < 0) + if (err) goto free_card; err = mmc_decode_cid(card); - if (err < 0) + if (err) goto free_card; } /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto free_card; + } if (!oldcard) { /* - * Fetch and process extened CSD. + * Fetch and process extended CSD. */ err = mmc_read_ext_csd(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; } @@ -334,7 +370,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, (host->caps & MMC_CAP_MMC_HIGHSPEED)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_card_set_highspeed(card); @@ -363,7 +399,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, (host->caps & MMC_CAP_4_BIT_DATA)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); @@ -372,14 +408,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - return MMC_ERR_NONE; + return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - return MMC_ERR_FAILED; + return err; } /* @@ -413,7 +449,7 @@ static void mmc_detect(struct mmc_host *host) mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_remove(host); mmc_claim_host(host); @@ -480,7 +516,8 @@ static void mmc_suspend(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } @@ -499,14 +536,17 @@ static void mmc_resume(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - err = mmc_init_card(host, host->ocr, host->card); - if (err != MMC_ERR_NONE) { + mmc_release_host(host); + + if (err) { mmc_remove(host); + + mmc_claim_host(host); mmc_detach_bus(host); + mmc_release_host(host); } - mmc_release_host(host); } #else @@ -533,11 +573,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) int err; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_ops); /* + * We need to get OCR a different way for SPI. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_read_ocr(host, 1, &ocr); + if (err) + goto err; + } + + /* * Sanity check the voltages that the card claims to * support. */ @@ -553,32 +602,37 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) /* * Can we support the voltage of the card? */ - if (!host->ocr) + if (!host->ocr) { + err = -EINVAL; goto err; + } /* * Detect and init the card. */ err = mmc_init_card(host, host->ocr, NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; mmc_release_host(host); err = mmc_add_card(host->card); if (err) - goto reclaim_host; + goto remove_card; return 0; -reclaim_host: - mmc_claim_host(host); +remove_card: mmc_remove_card(host->card); host->card = NULL; + mmc_claim_host(host); err: mmc_detach_bus(host); mmc_release_host(host); - return 0; + printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", + mmc_hostname(host), err); + + return err; } |