diff options
Diffstat (limited to 'drivers/mmc')
43 files changed, 1884 insertions, 2246 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index dabec556ebb8..f1c84decb192 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -384,7 +384,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, md = mmc_blk_get(bdev->bd_disk); if (!md) { err = -EINVAL; - goto cmd_done; + goto cmd_err; } card = md->queue.card; @@ -483,6 +483,7 @@ cmd_rel_host: cmd_done: mmc_blk_put(md); +cmd_err: kfree(idata->buf); kfree(idata); return err; @@ -553,7 +554,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; - unsigned int timeout_us; struct scatterlist sg; @@ -573,23 +573,12 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) cmd.arg = 0; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; - data.timeout_ns = card->csd.tacc_ns * 100; - data.timeout_clks = card->csd.tacc_clks * 100; - - timeout_us = data.timeout_ns / 1000; - timeout_us += data.timeout_clks * 1000 / - (card->host->ios.clock / 1000); - - if (timeout_us > 100000) { - data.timeout_ns = 100000000; - data.timeout_clks = 0; - } - data.blksz = 4; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; + mmc_set_data_timeout(&data, card); mrq.cmd = &cmd; mrq.data = &data; @@ -861,9 +850,7 @@ out: goto retry; if (!err) mmc_blk_reset_success(md, type); - spin_lock_irq(&md->lock); - __blk_end_request(req, err, blk_rq_bytes(req)); - spin_unlock_irq(&md->lock); + blk_end_request(req, err, blk_rq_bytes(req)); return err ? 0 : 1; } @@ -945,9 +932,7 @@ out_retry: if (!err) mmc_blk_reset_success(md, type); out: - spin_lock_irq(&md->lock); - __blk_end_request(req, err, blk_rq_bytes(req)); - spin_unlock_irq(&md->lock); + blk_end_request(req, err, blk_rq_bytes(req)); return err ? 0 : 1; } @@ -962,9 +947,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) if (ret) ret = -EIO; - spin_lock_irq(&md->lock); - __blk_end_request_all(req, ret); - spin_unlock_irq(&md->lock); + blk_end_request_all(req, ret); return ret ? 0 : 1; } @@ -1263,14 +1246,10 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, blocks = mmc_sd_num_wr_blocks(card); if (blocks != (u32)-1) { - spin_lock_irq(&md->lock); - ret = __blk_end_request(req, 0, blocks << 9); - spin_unlock_irq(&md->lock); + ret = blk_end_request(req, 0, blocks << 9); } } else { - spin_lock_irq(&md->lock); - ret = __blk_end_request(req, 0, brq->data.bytes_xfered); - spin_unlock_irq(&md->lock); + ret = blk_end_request(req, 0, brq->data.bytes_xfered); } return ret; } @@ -1283,7 +1262,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) int ret = 1, disable_multi = 0, retry = 0, type; enum mmc_blk_status status; struct mmc_queue_req *mq_rq; - struct request *req; + struct request *req = rqc; struct mmc_async_req *areq; if (!rqc && !mq->mqrq_prev->req) @@ -1291,6 +1270,16 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) do { if (rqc) { + /* + * When 4KB native sector is enabled, only 8 blocks + * multiple read or write is allowed + */ + if ((brq->data.blocks & 0x07) && + (card->ext_csd.data_sector_size == 4096)) { + pr_err("%s: Transfer size is not 4KB sector size aligned\n", + req->rq_disk->disk_name); + goto cmd_abort; + } mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); areq = &mq->mqrq_cur->mmc_active; } else @@ -1312,10 +1301,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) * A block was successfully transferred. */ mmc_blk_reset_success(md, type); - spin_lock_irq(&md->lock); - ret = __blk_end_request(req, 0, + ret = blk_end_request(req, 0, brq->data.bytes_xfered); - spin_unlock_irq(&md->lock); /* * If the blk_end_request function returns non-zero even * though all data has been transferred and no errors @@ -1365,10 +1352,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) * time, so we only reach here after trying to * read a single sector. */ - spin_lock_irq(&md->lock); - ret = __blk_end_request(req, -EIO, + ret = blk_end_request(req, -EIO, brq->data.blksz); - spin_unlock_irq(&md->lock); if (!ret) goto start_new_req; break; @@ -1389,12 +1374,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) return 1; cmd_abort: - spin_lock_irq(&md->lock); if (mmc_card_removed(card)) req->cmd_flags |= REQ_QUIET; while (ret) - ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); - spin_unlock_irq(&md->lock); + ret = blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); start_new_req: if (rqc) { @@ -1418,9 +1401,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ret = mmc_blk_part_switch(card, md); if (ret) { if (req) { - spin_lock_irq(&md->lock); - __blk_end_request_all(req, -EIO); - spin_unlock_irq(&md->lock); + blk_end_request_all(req, -EIO); } ret = 0; goto out; @@ -1538,7 +1519,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), "mmcblk%d%s", md->name_idx, subname ? subname : ""); - blk_queue_logical_block_size(md->queue.queue, 512); + if (mmc_card_mmc(card)) + blk_queue_logical_block_size(md->queue.queue, + card->ext_csd.data_sector_size); + else + blk_queue_logical_block_size(md->queue.queue, 512); + set_capacity(md->disk, size); if (mmc_host_cmd23(card->host)) { diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 996f8e36e23d..e360a979857d 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -96,7 +96,7 @@ static int mmc_queue_thread(void *d) * on any queue on this host, and attempt to issue it. This may * not be the queue we were asked to process. */ -static void mmc_request(struct request_queue *q) +static void mmc_request_fn(struct request_queue *q) { struct mmc_queue *mq = q->queuedata; struct request *req; @@ -171,12 +171,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, limit = *mmc_dev(host)->dma_mask; mq->card = card; - mq->queue = blk_init_queue(mmc_request, lock); + mq->queue = blk_init_queue(mmc_request_fn, lock); if (!mq->queue) return -ENOMEM; - memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur)); - memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev)); mq->mqrq_cur = mqrq_cur; mq->mqrq_prev = mqrq_prev; mq->queue->queuedata = mq; diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index dca4428380f1..38ed210ce2f3 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ - quirks.o cd-gpio.o + quirks.o slot-gpio.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index c60cee92a2b2..9b68933f27e7 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -122,6 +122,7 @@ static int mmc_bus_remove(struct device *dev) return 0; } +#ifdef CONFIG_PM_SLEEP static int mmc_bus_suspend(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); @@ -143,6 +144,7 @@ static int mmc_bus_resume(struct device *dev) ret = drv->resume(card); return ret; } +#endif #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c deleted file mode 100644 index 2c14be73254c..000000000000 --- a/drivers/mmc/core/cd-gpio.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Generic GPIO card-detect helper - * - * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/err.h> -#include <linux/gpio.h> -#include <linux/interrupt.h> -#include <linux/jiffies.h> -#include <linux/mmc/cd-gpio.h> -#include <linux/mmc/host.h> -#include <linux/module.h> -#include <linux/slab.h> - -struct mmc_cd_gpio { - unsigned int gpio; - char label[0]; -}; - -static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id) -{ - /* Schedule a card detection after a debounce timeout */ - mmc_detect_change(dev_id, msecs_to_jiffies(100)); - return IRQ_HANDLED; -} - -int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio) -{ - size_t len = strlen(dev_name(host->parent)) + 4; - struct mmc_cd_gpio *cd; - int irq = gpio_to_irq(gpio); - int ret; - - if (irq < 0) - return irq; - - cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL); - if (!cd) - return -ENOMEM; - - snprintf(cd->label, len, "%s cd", dev_name(host->parent)); - - ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label); - if (ret < 0) - goto egpioreq; - - ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - cd->label, host); - if (ret < 0) - goto eirqreq; - - cd->gpio = gpio; - host->hotplug.irq = irq; - host->hotplug.handler_priv = cd; - - return 0; - -eirqreq: - gpio_free(gpio); -egpioreq: - kfree(cd); - return ret; -} -EXPORT_SYMBOL(mmc_cd_gpio_request); - -void mmc_cd_gpio_free(struct mmc_host *host) -{ - struct mmc_cd_gpio *cd = host->hotplug.handler_priv; - - free_irq(host->hotplug.irq, host); - gpio_free(cd->gpio); - kfree(cd); -} -EXPORT_SYMBOL(mmc_cd_gpio_free); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ba821fe70bca..8ac5246e2ab2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -42,6 +42,7 @@ #include "sdio_ops.h" static struct workqueue_struct *workqueue; +static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* * Enabling software CRCs on the data blocks can be a significant (30%) @@ -403,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card) { int err; u32 status; + unsigned long prg_wait; BUG_ON(!card); @@ -418,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card) goto out; } - /* - * If the card status is in PRG-state, we can send the HPI command. - */ - if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { - do { - /* - * We don't know when the HPI command will finish - * processing, so we need to resend HPI until out - * of prg-state, and keep checking the card status - * with SEND_STATUS. If a timeout error occurs when - * sending the HPI command, we are already out of - * prg-state. - */ - err = mmc_send_hpi_cmd(card, &status); - if (err) - pr_debug("%s: abort HPI (%d error)\n", - mmc_hostname(card->host), err); + switch (R1_CURRENT_STATE(status)) { + case R1_STATE_IDLE: + case R1_STATE_READY: + case R1_STATE_STBY: + /* + * In idle states, HPI is not needed and the caller + * can issue the next intended command immediately + */ + goto out; + case R1_STATE_PRG: + break; + default: + /* In all other states, it's illegal to issue HPI */ + pr_debug("%s: HPI cannot be sent. Card state=%d\n", + mmc_hostname(card->host), R1_CURRENT_STATE(status)); + err = -EINVAL; + goto out; + } - err = mmc_send_status(card, &status); - if (err) - break; - } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); - } else - pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); + err = mmc_send_hpi_cmd(card, &status); + if (err) + goto out; + + prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time); + do { + err = mmc_send_status(card, &status); + + if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN) + break; + if (time_after(jiffies, prg_wait)) + err = -ETIMEDOUT; + } while (!err); out: mmc_release_host(card->host); @@ -940,7 +950,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply) return result; } -EXPORT_SYMBOL(mmc_regulator_get_ocrmask); +EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask); /** * mmc_regulator_set_ocr - set regulator to match host->ios voltage @@ -1010,7 +1020,30 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, "could not set regulator OCR (%d)\n", result); return result; } -EXPORT_SYMBOL(mmc_regulator_set_ocr); +EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); + +int mmc_regulator_get_supply(struct mmc_host *mmc) +{ + struct device *dev = mmc_dev(mmc); + struct regulator *supply; + int ret; + + supply = devm_regulator_get(dev, "vmmc"); + mmc->supply.vmmc = supply; + mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc"); + + if (IS_ERR(supply)) + return PTR_ERR(supply); + + ret = mmc_regulator_get_ocrmask(supply); + if (ret > 0) + mmc->ocr_avail = ret; + else + dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret); + + return 0; +} +EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); #endif /* CONFIG_REGULATOR */ @@ -1157,6 +1190,9 @@ static void mmc_power_up(struct mmc_host *host) { int bit; + if (host->ios.power_mode == MMC_POWER_ON) + return; + mmc_host_clk_hold(host); /* If ocr is set, we use it */ @@ -1176,6 +1212,9 @@ static void mmc_power_up(struct mmc_host *host) host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); + /* Set signal voltage to 3.3V */ + mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false); + /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. @@ -1199,6 +1238,10 @@ static void mmc_power_up(struct mmc_host *host) void mmc_power_off(struct mmc_host *host) { int err = 0; + + if (host->ios.power_mode == MMC_POWER_OFF) + return; + mmc_host_clk_hold(host); host->ios.clock = 0; @@ -1923,9 +1966,6 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) */ mmc_hw_reset_for_init(host); - /* Initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - /* * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 @@ -2005,7 +2045,6 @@ EXPORT_SYMBOL(mmc_detect_card_removed); void mmc_rescan(struct work_struct *work) { - static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; struct mmc_host *host = container_of(work, struct mmc_host, detect.work); int i; @@ -2044,8 +2083,12 @@ void mmc_rescan(struct work_struct *work) */ mmc_bus_put(host); - if (host->ops->get_cd && host->ops->get_cd(host) == 0) + if (host->ops->get_cd && host->ops->get_cd(host) == 0) { + mmc_claim_host(host); + mmc_power_off(host); + mmc_release_host(host); goto out; + } mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { @@ -2063,7 +2106,9 @@ void mmc_rescan(struct work_struct *work) void mmc_start_host(struct mmc_host *host) { - mmc_power_off(host); + host->f_init = max(freqs[0], host->f_min); + host->rescan_disable = 0; + mmc_power_up(host); mmc_detect_change(host, 0); } @@ -2076,6 +2121,7 @@ void mmc_stop_host(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); #endif + host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); mmc_flush_scheduled_work(); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 91c84c7a1829..597f189b4427 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -32,6 +32,7 @@ static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); + mutex_destroy(&host->slot.lock); kfree(host); } @@ -312,6 +313,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (!host) return NULL; + /* scanning will be enabled when we're ready */ + host->rescan_disable = 1; spin_lock(&mmc_host_lock); err = idr_get_new(&mmc_host_idr, host, &host->index); spin_unlock(&mmc_host_lock); @@ -327,6 +330,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) mmc_host_clk_init(host); + mutex_init(&host->slot.lock); + host->slot.cd_irq = -EINVAL; + spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 54df5adc0413..396b25891bb9 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -235,6 +235,36 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) return err; } +static void mmc_select_card_type(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK; + unsigned int caps = host->caps, caps2 = host->caps2; + unsigned int hs_max_dtr = 0; + + if (card_type & EXT_CSD_CARD_TYPE_26) + hs_max_dtr = MMC_HIGH_26_MAX_DTR; + + if (caps & MMC_CAP_MMC_HIGHSPEED && + card_type & EXT_CSD_CARD_TYPE_52) + hs_max_dtr = MMC_HIGH_52_MAX_DTR; + + if ((caps & MMC_CAP_1_8V_DDR && + card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) || + (caps & MMC_CAP_1_2V_DDR && + card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)) + hs_max_dtr = MMC_HIGH_DDR_MAX_DTR; + + if ((caps2 & MMC_CAP2_HS200_1_8V_SDR && + card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) || + (caps2 & MMC_CAP2_HS200_1_2V_SDR && + card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)) + hs_max_dtr = MMC_HS200_MAX_DTR; + + card->ext_csd.hs_max_dtr = hs_max_dtr; + card->ext_csd.card_type = card_type; +} + /* * Decode extended CSD. */ @@ -284,56 +314,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } + card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; - switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { - case EXT_CSD_CARD_TYPE_SDR_ALL: - case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V: - case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V: - case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52: - card->ext_csd.hs_max_dtr = 200000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200; - break; - case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL: - case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V: - case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V: - case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52: - card->ext_csd.hs_max_dtr = 200000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V; - break; - case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL: - case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V: - case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V: - case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52: - card->ext_csd.hs_max_dtr = 200000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V; - break; - case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | - EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52; - break; - case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 | - EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V; - break; - case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 | - EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V; - break; - case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 52000000; - break; - case EXT_CSD_CARD_TYPE_26: - card->ext_csd.hs_max_dtr = 26000000; - break; - default: - /* MMC v4 spec says this cannot happen */ - pr_warning("%s: card is mmc v4 but doesn't " - "support any high-speed modes.\n", - mmc_hostname(card->host)); - } + mmc_select_card_type(card); card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = @@ -533,6 +516,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } else { card->ext_csd.data_tag_unit_size = 0; } + } else { + card->ext_csd.data_sector_size = 512; } out: @@ -556,14 +541,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) err = mmc_get_ext_csd(card, &bw_ext_csd); if (err || bw_ext_csd == NULL) { - if (bus_width != MMC_BUS_WIDTH_1) - err = -EINVAL; + err = -EINVAL; goto out; } - if (bus_width == MMC_BUS_WIDTH_1) - goto out; - /* only compare read only fields */ err = !((card->ext_csd.raw_partition_support == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && @@ -745,7 +726,7 @@ static int mmc_select_powerclass(struct mmc_card *card, */ static int mmc_select_hs200(struct mmc_card *card) { - int idx, err = 0; + int idx, err = -EINVAL; struct mmc_host *host; static unsigned ext_csd_bits[] = { EXT_CSD_BUS_WIDTH_4, @@ -761,10 +742,12 @@ static int mmc_select_hs200(struct mmc_card *card) host = card->host; if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V && - host->caps2 & MMC_CAP2_HS200_1_2V_SDR) - if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0)) - err = mmc_set_signal_voltage(host, - MMC_SIGNAL_VOLTAGE_180, 0); + host->caps2 & MMC_CAP2_HS200_1_2V_SDR) + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0); + + if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V && + host->caps2 & MMC_CAP2_HS200_1_8V_SDR) + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, 0); /* If fails try again during next card power cycle */ if (err) @@ -835,9 +818,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!mmc_host_is_spi(host)) mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); - /* Initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - /* * Since we're changing the OCR value, we seem to * need to tell some cards to go back to the idle @@ -1347,7 +1327,7 @@ static int mmc_suspend(struct mmc_host *host) if (!err) mmc_card_set_sleep(host->card); } else if (!mmc_host_is_spi(host)) - mmc_deselect_cards(host); + err = mmc_deselect_cards(host); host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); mmc_release_host(host); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 69370f494e05..0ed2cc5f35b6 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) cmd.opcode = opcode; cmd.arg = card->rca << 16 | 1; - cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c272c6868ecf..74972c241dff 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -244,7 +244,7 @@ static int mmc_read_ssr(struct mmc_card *card) * bitfield positions accordingly. */ au = UNSTUFF_BITS(ssr, 428 - 384, 4); - if (au > 0 || au <= 9) { + if (au > 0 && au <= 9) { card->ssr.au = 1 << (au + 4); es = UNSTUFF_BITS(ssr, 408 - 384, 16); et = UNSTUFF_BITS(ssr, 402 - 384, 6); @@ -290,8 +290,12 @@ static int mmc_read_switch(struct mmc_card *card) return -ENOMEM; } - /* Find out the supported Bus Speed Modes. */ - err = mmc_sd_switch(card, 0, 0, 1, status); + /* + * Find out the card's support bits with a mode 0 operation. + * The argument does not matter, as the support bits do not + * change with the arguments. + */ + err = mmc_sd_switch(card, 0, 0, 0, status); if (err) { /* * If the host or the card can't do the switch, @@ -312,46 +316,8 @@ static int mmc_read_switch(struct mmc_card *card) if (card->scr.sda_spec3) { card->sw_caps.sd3_bus_mode = status[13]; - - /* Find out Driver Strengths supported by the card */ - err = mmc_sd_switch(card, 0, 2, 1, status); - if (err) { - /* - * If the host or the card can't do the switch, - * fail more gracefully. - */ - if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) - goto out; - - pr_warning("%s: problem reading " - "Driver Strength.\n", - mmc_hostname(card->host)); - err = 0; - - goto out; - } - + /* Driver Strengths supported by the card */ card->sw_caps.sd3_drv_type = status[9]; - - /* Find out Current Limits supported by the card */ - err = mmc_sd_switch(card, 0, 3, 1, status); - if (err) { - /* - * If the host or the card can't do the switch, - * fail more gracefully. - */ - if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) - goto out; - - pr_warning("%s: problem reading " - "Current Limit.\n", - mmc_hostname(card->host)); - err = 0; - - goto out; - } - - card->sw_caps.sd3_curr_limit = status[7]; } out: @@ -551,60 +517,80 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) return 0; } +/* Get host's max current setting at its current voltage */ +static u32 sd_get_host_max_current(struct mmc_host *host) +{ + u32 voltage, max_current; + + voltage = 1 << host->ios.vdd; + switch (voltage) { + case MMC_VDD_165_195: + max_current = host->max_current_180; + break; + case MMC_VDD_29_30: + case MMC_VDD_30_31: + max_current = host->max_current_300; + break; + case MMC_VDD_32_33: + case MMC_VDD_33_34: + max_current = host->max_current_330; + break; + default: + max_current = 0; + } + + return max_current; +} + static int sd_set_current_limit(struct mmc_card *card, u8 *status) { - int current_limit = 0; + int current_limit = SD_SET_CURRENT_NO_CHANGE; int err; + u32 max_current; /* * Current limit switch is only defined for SDR50, SDR104, and DDR50 - * bus speed modes. For other bus speed modes, we set the default - * current limit of 200mA. + * bus speed modes. For other bus speed modes, we do not change the + * current limit. */ - if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) || - (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) || - (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) { - if (card->host->caps & MMC_CAP_MAX_CURRENT_800) { - if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800) - current_limit = SD_SET_CURRENT_LIMIT_800; - else if (card->sw_caps.sd3_curr_limit & - SD_MAX_CURRENT_600) - current_limit = SD_SET_CURRENT_LIMIT_600; - else if (card->sw_caps.sd3_curr_limit & - SD_MAX_CURRENT_400) - current_limit = SD_SET_CURRENT_LIMIT_400; - else if (card->sw_caps.sd3_curr_limit & - SD_MAX_CURRENT_200) - current_limit = SD_SET_CURRENT_LIMIT_200; - } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) { - if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600) - current_limit = SD_SET_CURRENT_LIMIT_600; - else if (card->sw_caps.sd3_curr_limit & - SD_MAX_CURRENT_400) - current_limit = SD_SET_CURRENT_LIMIT_400; - else if (card->sw_caps.sd3_curr_limit & - SD_MAX_CURRENT_200) - current_limit = SD_SET_CURRENT_LIMIT_200; - } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) { - if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400) - current_limit = SD_SET_CURRENT_LIMIT_400; - else if (card->sw_caps.sd3_curr_limit & - SD_MAX_CURRENT_200) - current_limit = SD_SET_CURRENT_LIMIT_200; - } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) { - if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200) - current_limit = SD_SET_CURRENT_LIMIT_200; - } - } else + if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) && + (card->sd_bus_speed != UHS_SDR104_BUS_SPEED) && + (card->sd_bus_speed != UHS_DDR50_BUS_SPEED)) + return 0; + + /* + * Host has different current capabilities when operating at + * different voltages, so find out its max current first. + */ + max_current = sd_get_host_max_current(card->host); + + /* + * We only check host's capability here, if we set a limit that is + * higher than the card's maximum current, the card will be using its + * maximum current, e.g. if the card's maximum current is 300ma, and + * when we set current limit to 200ma, the card will draw 200ma, and + * when we set current limit to 400/600/800ma, the card will draw its + * maximum 300ma from the host. + */ + if (max_current >= 800) + current_limit = SD_SET_CURRENT_LIMIT_800; + else if (max_current >= 600) + current_limit = SD_SET_CURRENT_LIMIT_600; + else if (max_current >= 400) + current_limit = SD_SET_CURRENT_LIMIT_400; + else if (max_current >= 200) current_limit = SD_SET_CURRENT_LIMIT_200; - err = mmc_sd_switch(card, 1, 3, current_limit, status); - if (err) - return err; + if (current_limit != SD_SET_CURRENT_NO_CHANGE) { + err = mmc_sd_switch(card, 1, 3, current_limit, status); + if (err) + return err; - if (((status[15] >> 4) & 0x0F) != current_limit) - pr_warning("%s: Problem setting current limit!\n", - mmc_hostname(card->host)); + if (((status[15] >> 4) & 0x0F) != current_limit) + pr_warning("%s: Problem setting current limit!\n", + mmc_hostname(card->host)); + + } return 0; } @@ -726,6 +712,7 @@ struct device_type sd_type = { int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) { int err; + u32 max_current; /* * Since we're changing the OCR value, we seem to @@ -753,9 +740,12 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)) ocr |= SD_OCR_S18R; - /* If the host can supply more than 150mA, XPC should be set to 1. */ - if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 | - MMC_CAP_SET_XPC_180)) + /* + * If the host can supply more than 150mA at current voltage, + * XPC should be set to 1. + */ + max_current = sd_get_host_max_current(host); + if (max_current > 150) ocr |= SD_OCR_XPC; try_again: @@ -911,9 +901,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, BUG_ON(!host); WARN_ON(!host->claimed); - /* The initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - err = mmc_sd_get_cid(host, ocr, cid, &rocr); if (err) return err; @@ -1075,16 +1062,18 @@ static void mmc_sd_detect(struct mmc_host *host) */ static int mmc_sd_suspend(struct mmc_host *host) { + int err = 0; + BUG_ON(!host); BUG_ON(!host->card); mmc_claim_host(host); if (!mmc_host_is_spi(host)) - mmc_deselect_cards(host); + err = mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); - return 0; + return err; } /* diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2c7c83f832d2..d4619e2ec030 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -218,6 +218,12 @@ static int sdio_enable_wide(struct mmc_card *card) if (ret) return ret; + if ((ctrl & SDIO_BUS_WIDTH_MASK) == SDIO_BUS_WIDTH_RESERVED) + pr_warning("%s: SDIO_CCCR_IF is invalid: 0x%02x\n", + mmc_hostname(card->host), ctrl); + + /* set as 4-bit bus width */ + ctrl &= ~SDIO_BUS_WIDTH_MASK; ctrl |= SDIO_BUS_WIDTH_4BIT; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); @@ -585,9 +591,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, * Inform the card of the voltage */ if (!powered_resume) { - /* The initialization should be done at 3.3 V I/O voltage. */ - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - err = mmc_send_io_op_cond(host, host->ocr, &ocr); if (err) goto err; @@ -947,7 +950,7 @@ static int mmc_sdio_resume(struct mmc_host *host) } if (!err && host->sdio_irqs) - mmc_signal_sdio_irq(host); + wake_up_process(host->sdio_irq_thread); mmc_release_host(host); /* @@ -1000,10 +1003,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * restore the correct voltage setting of the card. */ - /* The initialization should be done at 3.3 V I/O voltage. */ - if (!mmc_card_keep_power(host)) - mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); - sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index f1c7ed8f4d85..8e94e555b788 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) if (ret == -ENOENT) { /* warn about unknown tuples */ - pr_warning("%s: queuing unknown" + pr_warn_ratelimited("%s: queuing unknown" " CIS tuple 0x%02x (%u bytes)\n", mmc_hostname(card->host), tpl_code, tpl_link); diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index f573e7f9f740..3d8ceb4084de 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -28,18 +28,20 @@ #include "sdio_ops.h" -static int process_sdio_pending_irqs(struct mmc_card *card) +static int process_sdio_pending_irqs(struct mmc_host *host) { + struct mmc_card *card = host->card; int i, ret, count; unsigned char pending; struct sdio_func *func; /* * Optimization, if there is only 1 function interrupt registered - * call irq handler directly + * and we know an IRQ was signaled then call irq handler directly. + * Otherwise do the full probe. */ func = card->sdio_single_irq; - if (func) { + if (func && host->sdio_irq_pending) { func->irq_handler(func); return 1; } @@ -116,7 +118,8 @@ static int sdio_irq_thread(void *_host) ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort); if (ret) break; - ret = process_sdio_pending_irqs(host->card); + ret = process_sdio_pending_irqs(host); + host->sdio_irq_pending = false; mmc_release_host(host); /* diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c new file mode 100644 index 000000000000..058242916cef --- /dev/null +++ b/drivers/mmc/core/slot-gpio.c @@ -0,0 +1,188 @@ +/* + * Generic GPIO card-detect helper + * + * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/mmc/host.h> +#include <linux/mmc/slot-gpio.h> +#include <linux/module.h> +#include <linux/slab.h> + +struct mmc_gpio { + int ro_gpio; + int cd_gpio; + char *ro_label; + char cd_label[0]; +}; + +static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) +{ + /* Schedule a card detection after a debounce timeout */ + mmc_detect_change(dev_id, msecs_to_jiffies(100)); + return IRQ_HANDLED; +} + +static int mmc_gpio_alloc(struct mmc_host *host) +{ + size_t len = strlen(dev_name(host->parent)) + 4; + struct mmc_gpio *ctx; + + mutex_lock(&host->slot.lock); + + ctx = host->slot.handler_priv; + if (!ctx) { + /* + * devm_kzalloc() can be called after device_initialize(), even + * before device_add(), i.e., between mmc_alloc_host() and + * mmc_add_host() + */ + ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len, + GFP_KERNEL); + if (ctx) { + ctx->ro_label = ctx->cd_label + len; + snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); + snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); + ctx->cd_gpio = -EINVAL; + ctx->ro_gpio = -EINVAL; + host->slot.handler_priv = ctx; + } + } + + mutex_unlock(&host->slot.lock); + + return ctx ? 0 : -ENOMEM; +} + +int mmc_gpio_get_ro(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx || !gpio_is_valid(ctx->ro_gpio)) + return -ENOSYS; + + return !gpio_get_value_cansleep(ctx->ro_gpio) ^ + !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); +} +EXPORT_SYMBOL(mmc_gpio_get_ro); + +int mmc_gpio_get_cd(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx || !gpio_is_valid(ctx->cd_gpio)) + return -ENOSYS; + + return !gpio_get_value_cansleep(ctx->cd_gpio) ^ + !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); +} +EXPORT_SYMBOL(mmc_gpio_get_cd); + +int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) +{ + struct mmc_gpio *ctx; + int ret; + + if (!gpio_is_valid(gpio)) + return -EINVAL; + + ret = mmc_gpio_alloc(host); + if (ret < 0) + return ret; + + ctx = host->slot.handler_priv; + + return gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label); +} +EXPORT_SYMBOL(mmc_gpio_request_ro); + +int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) +{ + struct mmc_gpio *ctx; + int irq = gpio_to_irq(gpio); + int ret; + + ret = mmc_gpio_alloc(host); + if (ret < 0) + return ret; + + ctx = host->slot.handler_priv; + + ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label); + if (ret < 0) + /* + * don't bother freeing memory. It might still get used by other + * slot functions, in any case it will be freed, when the device + * is destroyed. + */ + return ret; + + /* + * Even if gpio_to_irq() returns a valid IRQ number, the platform might + * still prefer to poll, e.g., because that IRQ number is already used + * by another unit and cannot be shared. + */ + if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) + irq = -EINVAL; + + if (irq >= 0) { + ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ctx->cd_label, host); + if (ret < 0) + irq = ret; + } + + host->slot.cd_irq = irq; + + if (irq < 0) + host->caps |= MMC_CAP_NEEDS_POLL; + + ctx->cd_gpio = gpio; + + return 0; +} +EXPORT_SYMBOL(mmc_gpio_request_cd); + +void mmc_gpio_free_ro(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + int gpio; + + if (!ctx || !gpio_is_valid(ctx->ro_gpio)) + return; + + gpio = ctx->ro_gpio; + ctx->ro_gpio = -EINVAL; + + gpio_free(gpio); +} +EXPORT_SYMBOL(mmc_gpio_free_ro); + +void mmc_gpio_free_cd(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + int gpio; + + if (!ctx || !gpio_is_valid(ctx->cd_gpio)) + return; + + if (host->slot.cd_irq >= 0) { + free_irq(host->slot.cd_irq, host); + host->slot.cd_irq = -EINVAL; + } + + gpio = ctx->cd_gpio; + ctx->cd_gpio = -EINVAL; + + gpio_free(gpio); +} +EXPORT_SYMBOL(mmc_gpio_free_cd); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2bc06e7344db..aa131b32e3b2 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -278,10 +278,13 @@ choice Choose which driver to use for the Atmel MCI Silicon config MMC_AT91 - tristate "AT91 SD/MMC Card Interface support" + tristate "AT91 SD/MMC Card Interface support (DEPRECATED)" depends on ARCH_AT91 help - This selects the AT91 MCI controller. + This selects the AT91 MCI controller. This driver will + be removed soon (for more information have a look to + Documentation/feature-removal-schedule.txt). Please use + MMC_ATMEL_MCI. If unsure, say N. @@ -307,16 +310,6 @@ config MMC_ATMELMCI_DMA If unsure, say N. -config MMC_IMX - tristate "Motorola i.MX Multimedia Card Interface support" - depends on ARCH_MX1 - help - This selects the Motorola i.MX Multimedia card Interface. - If you have a i.MX platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - config MMC_MSM tristate "Qualcomm SDCC Controller Support" depends on MMC && ARCH_MSM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3e7e26d08073..8922b06be925 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o -obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index 787aba1682bb..ab56f7db5315 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -140,4 +140,18 @@ #define atmci_writel(port,reg,value) \ __raw_writel((value), (port)->regs + reg) +/* + * Fix sconfig's burst size according to atmel MCI. We need to convert them as: + * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. + * + * This can be done by finding most significant bit set. + */ +static inline unsigned int atmci_convert_chksize(unsigned int maxburst) +{ + if (maxburst > 1) + return fls(maxburst) - 2; + else + return 0; +} + #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index e94476beca18..322412cec4ee 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -45,19 +45,19 @@ #define ATMCI_DMA_THRESHOLD 16 enum { - EVENT_CMD_COMPLETE = 0, + EVENT_CMD_RDY = 0, EVENT_XFER_COMPLETE, - EVENT_DATA_COMPLETE, + EVENT_NOTBUSY, EVENT_DATA_ERROR, }; enum atmel_mci_state { STATE_IDLE = 0, STATE_SENDING_CMD, - STATE_SENDING_DATA, - STATE_DATA_BUSY, + STATE_DATA_XFER, + STATE_WAITING_NOTBUSY, STATE_SENDING_STOP, - STATE_DATA_ERROR, + STATE_END_REQUEST, }; enum atmci_xfer_dir { @@ -78,6 +78,9 @@ struct atmel_mci_caps { bool has_highspeed; bool has_rwproof; bool has_odd_clk_div; + bool has_bad_data_ordering; + bool need_reset_after_xfer; + bool need_blksz_mul_4; }; struct atmel_mci_dma { @@ -91,6 +94,11 @@ struct atmel_mci_dma { * @regs: Pointer to MMIO registers. * @sg: Scatterlist entry currently being processed by PIO or PDC code. * @pio_offset: Offset into the current scatterlist entry. + * @buffer: Buffer used if we don't have the r/w proof capability. We + * don't have the time to switch pdc buffers so we have to use only + * one buffer for the full transaction. + * @buf_size: size of the buffer. + * @phys_buf_addr: buffer address needed for pdc. * @cur_slot: The slot which is currently using the controller. * @mrq: The request currently being processed on @cur_slot, * or NULL if the controller is idle. @@ -116,6 +124,7 @@ struct atmel_mci_dma { * @queue: List of slots waiting for access to the controller. * @need_clock_update: Update the clock rate before the next request. * @need_reset: Reset controller before next request. + * @timer: Timer to balance the data timeout error flag which cannot rise. * @mode_reg: Value of the MR register. * @cfg_reg: Value of the CFG register. * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus @@ -166,6 +175,9 @@ struct atmel_mci { struct scatterlist *sg; unsigned int pio_offset; + unsigned int *buffer; + unsigned int buf_size; + dma_addr_t buf_phys_addr; struct atmel_mci_slot *cur_slot; struct mmc_request *mrq; @@ -189,6 +201,7 @@ struct atmel_mci { bool need_clock_update; bool need_reset; + struct timer_list timer; u32 mode_reg; u32 cfg_reg; unsigned long bus_hz; @@ -378,11 +391,17 @@ static int atmci_regs_show(struct seq_file *s, void *v) clk_disable(host->mck); spin_unlock_bh(&host->lock); - seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", + seq_printf(s, "MR:\t0x%08x%s%s ", buf[ATMCI_MR / 4], buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", - buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "", - buf[ATMCI_MR / 4] & 0xff); + buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : ""); + if (host->caps.has_odd_clk_div) + seq_printf(s, "{CLKDIV,CLKODD}=%u\n", + ((buf[ATMCI_MR / 4] & 0xff) << 1) + | ((buf[ATMCI_MR / 4] >> 16) & 1)); + else + seq_printf(s, "CLKDIV=%u\n", + (buf[ATMCI_MR / 4] & 0xff)); seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]); seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]); @@ -480,6 +499,32 @@ err: dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); } +static inline unsigned int atmci_get_version(struct atmel_mci *host) +{ + return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; +} + +static void atmci_timeout_timer(unsigned long data) +{ + struct atmel_mci *host; + + host = (struct atmel_mci *)data; + + dev_dbg(&host->pdev->dev, "software timeout\n"); + + if (host->mrq->cmd->data) { + host->mrq->cmd->data->error = -ETIMEDOUT; + host->data = NULL; + } else { + host->mrq->cmd->error = -ETIMEDOUT; + host->cmd = NULL; + } + host->need_reset = 1; + host->state = STATE_END_REQUEST; + smp_wmb(); + tasklet_schedule(&host->tasklet); +} + static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, unsigned int ns) { @@ -591,6 +636,7 @@ static void atmci_send_command(struct atmel_mci *host, static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) { + dev_dbg(&host->pdev->dev, "send stop command\n"); atmci_send_command(host, data->stop, host->stop_cmdr); atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); } @@ -603,6 +649,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) { u32 pointer_reg, counter_reg; + unsigned int buf_size; if (dir == XFER_RECEIVE) { pointer_reg = ATMEL_PDC_RPR; @@ -617,8 +664,15 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, counter_reg += ATMEL_PDC_SCND_BUF_OFF; } - atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); - if (host->data_size <= sg_dma_len(host->sg)) { + if (!host->caps.has_rwproof) { + buf_size = host->buf_size; + atmci_writel(host, pointer_reg, host->buf_phys_addr); + } else { + buf_size = sg_dma_len(host->sg); + atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); + } + + if (host->data_size <= buf_size) { if (host->data_size & 0x3) { /* If size is different from modulo 4, transfer bytes */ atmci_writel(host, counter_reg, host->data_size); @@ -670,7 +724,20 @@ static void atmci_pdc_cleanup(struct atmel_mci *host) */ static void atmci_pdc_complete(struct atmel_mci *host) { + int transfer_size = host->data->blocks * host->data->blksz; + int i; + atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); + + if ((!host->caps.has_rwproof) + && (host->data->flags & MMC_DATA_READ)) { + if (host->caps.has_bad_data_ordering) + for (i = 0; i < transfer_size; i++) + host->buffer[i] = swab32(host->buffer[i]); + sg_copy_from_buffer(host->data->sg, host->data->sg_len, + host->buffer, transfer_size); + } + atmci_pdc_cleanup(host); /* @@ -678,9 +745,10 @@ static void atmci_pdc_complete(struct atmel_mci *host) * to send the stop command or waiting for NBUSY in this case. */ if (host->data) { + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); tasklet_schedule(&host->tasklet); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } } @@ -716,6 +784,8 @@ static void atmci_dma_complete(void *arg) * to send the stop command or waiting for NBUSY in this case. */ if (data) { + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); tasklet_schedule(&host->tasklet); @@ -791,6 +861,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) u32 iflags, tmp; unsigned int sg_len; enum dma_data_direction dir; + int i; data->error = -EINPROGRESS; @@ -806,7 +877,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; } else { dir = DMA_TO_DEVICE; - iflags |= ATMCI_ENDTX | ATMCI_TXBUFE; + iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; } /* Set BLKLEN */ @@ -818,6 +889,16 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) /* Configure PDC */ host->data_size = data->blocks * data->blksz; sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); + + if ((!host->caps.has_rwproof) + && (host->data->flags & MMC_DATA_WRITE)) { + sg_copy_to_buffer(host->data->sg, host->data->sg_len, + host->buffer, host->data_size); + if (host->caps.has_bad_data_ordering) + for (i = 0; i < host->data_size; i++) + host->buffer[i] = swab32(host->buffer[i]); + } + if (host->data_size) atmci_pdc_set_both_buf(host, ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); @@ -835,6 +916,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) enum dma_data_direction direction; enum dma_transfer_direction slave_dirn; unsigned int sglen; + u32 maxburst; u32 iflags; data->error = -EINPROGRESS; @@ -868,17 +950,18 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) if (!chan) return -ENODEV; - if (host->caps.has_dma) - atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); - if (data->flags & MMC_DATA_READ) { direction = DMA_FROM_DEVICE; host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; + maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst); } else { direction = DMA_TO_DEVICE; host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; + maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst); } + atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | ATMCI_DMAEN); + sglen = dma_map_sg(chan->device->dev, data->sg, data->sg_len, direction); @@ -931,6 +1014,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) static void atmci_stop_transfer(struct atmel_mci *host) { + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } @@ -940,8 +1025,7 @@ static void atmci_stop_transfer(struct atmel_mci *host) */ static void atmci_stop_transfer_pdc(struct atmel_mci *host) { - atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); } static void atmci_stop_transfer_dma(struct atmel_mci *host) @@ -953,6 +1037,8 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host) atmci_dma_cleanup(host); } else { /* Data transfer was stopped by the interrupt handler */ + dev_dbg(&host->pdev->dev, + "(%s) set pending xfer complete\n", __func__); atmci_set_pending(host, EVENT_XFER_COMPLETE); atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } @@ -977,9 +1063,12 @@ static void atmci_start_request(struct atmel_mci *host, host->pending_events = 0; host->completed_events = 0; + host->cmd_status = 0; host->data_status = 0; - if (host->need_reset) { + dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode); + + if (host->need_reset || host->caps.need_reset_after_xfer) { iflags = atmci_readl(host, ATMCI_IMR); iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); @@ -994,7 +1083,7 @@ static void atmci_start_request(struct atmel_mci *host, iflags = atmci_readl(host, ATMCI_IMR); if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) - dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", + dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", iflags); if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { @@ -1043,6 +1132,8 @@ static void atmci_start_request(struct atmel_mci *host, * prepared yet.) */ atmci_writel(host, ATMCI_IER, iflags); + + mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); } static void atmci_queue_request(struct atmel_mci *host, @@ -1057,6 +1148,7 @@ static void atmci_queue_request(struct atmel_mci *host, host->state = STATE_SENDING_CMD; atmci_start_request(host, slot); } else { + dev_dbg(&host->pdev->dev, "queue request\n"); list_add_tail(&slot->queue_node, &host->queue); } spin_unlock_bh(&host->lock); @@ -1069,6 +1161,7 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) struct mmc_data *data; WARN_ON(slot->mrq); + dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); /* * We may "know" the card is gone even though there's still an @@ -1308,6 +1401,8 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) host->state = STATE_IDLE; } + del_timer(&host->timer); + spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); @@ -1330,21 +1425,13 @@ static void atmci_command_complete(struct atmel_mci *host, cmd->error = -EILSEQ; else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) cmd->error = -EIO; - else - cmd->error = 0; - - if (cmd->error) { - dev_dbg(&host->pdev->dev, - "command error: status=0x%08x\n", status); - - if (cmd->data) { - host->stop_transfer(host); - host->data = NULL; - atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY - | ATMCI_TXRDY | ATMCI_RXRDY - | ATMCI_DATA_ERROR_FLAGS); + else if (host->mrq->data && (host->mrq->data->blksz & 3)) { + if (host->caps.need_blksz_mul_4) { + cmd->error = -EINVAL; + host->need_reset = 1; } - } + } else + cmd->error = 0; } static void atmci_detect_change(unsigned long data) @@ -1407,23 +1494,21 @@ static void atmci_detect_change(unsigned long data) break; case STATE_SENDING_CMD: mrq->cmd->error = -ENOMEDIUM; - if (!mrq->data) - break; - /* fall through */ - case STATE_SENDING_DATA: + if (mrq->data) + host->stop_transfer(host); + break; + case STATE_DATA_XFER: mrq->data->error = -ENOMEDIUM; host->stop_transfer(host); break; - case STATE_DATA_BUSY: - case STATE_DATA_ERROR: - if (mrq->data->error == -EINPROGRESS) - mrq->data->error = -ENOMEDIUM; - if (!mrq->stop) - break; - /* fall through */ + case STATE_WAITING_NOTBUSY: + mrq->data->error = -ENOMEDIUM; + break; case STATE_SENDING_STOP: mrq->stop->error = -ENOMEDIUM; break; + case STATE_END_REQUEST: + break; } atmci_request_end(host, mrq); @@ -1451,7 +1536,6 @@ static void atmci_tasklet_func(unsigned long priv) struct atmel_mci *host = (struct atmel_mci *)priv; struct mmc_request *mrq = host->mrq; struct mmc_data *data = host->data; - struct mmc_command *cmd = host->cmd; enum atmel_mci_state state = host->state; enum atmel_mci_state prev_state; u32 status; @@ -1467,107 +1551,186 @@ static void atmci_tasklet_func(unsigned long priv) do { prev_state = state; + dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state); switch (state) { case STATE_IDLE: break; case STATE_SENDING_CMD: + /* + * Command has been sent, we are waiting for command + * ready. Then we have three next states possible: + * END_REQUEST by default, WAITING_NOTBUSY if it's a + * command needing it or DATA_XFER if there is data. + */ + dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); if (!atmci_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) + EVENT_CMD_RDY)) break; + dev_dbg(&host->pdev->dev, "set completed cmd ready\n"); host->cmd = NULL; - atmci_set_completed(host, EVENT_CMD_COMPLETE); + atmci_set_completed(host, EVENT_CMD_RDY); atmci_command_complete(host, mrq->cmd); - if (!mrq->data || cmd->error) { - atmci_request_end(host, host->mrq); - goto unlock; - } + if (mrq->data) { + dev_dbg(&host->pdev->dev, + "command with data transfer"); + /* + * If there is a command error don't start + * data transfer. + */ + if (mrq->cmd->error) { + host->stop_transfer(host); + host->data = NULL; + atmci_writel(host, ATMCI_IDR, + ATMCI_TXRDY | ATMCI_RXRDY + | ATMCI_DATA_ERROR_FLAGS); + state = STATE_END_REQUEST; + } else + state = STATE_DATA_XFER; + } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { + dev_dbg(&host->pdev->dev, + "command response need waiting notbusy"); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + state = STATE_WAITING_NOTBUSY; + } else + state = STATE_END_REQUEST; - prev_state = state = STATE_SENDING_DATA; - /* fall through */ + break; - case STATE_SENDING_DATA: + case STATE_DATA_XFER: if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) { - host->stop_transfer(host); - if (data->stop) - atmci_send_stop_cmd(host, data); - state = STATE_DATA_ERROR; + dev_dbg(&host->pdev->dev, "set completed data error\n"); + atmci_set_completed(host, EVENT_DATA_ERROR); + state = STATE_END_REQUEST; break; } + /* + * A data transfer is in progress. The event expected + * to move to the next state depends of data transfer + * type (PDC or DMA). Once transfer done we can move + * to the next step which is WAITING_NOTBUSY in write + * case and directly SENDING_STOP in read case. + */ + dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n"); if (!atmci_test_and_clear_pending(host, EVENT_XFER_COMPLETE)) break; + dev_dbg(&host->pdev->dev, + "(%s) set completed xfer complete\n", + __func__); atmci_set_completed(host, EVENT_XFER_COMPLETE); - prev_state = state = STATE_DATA_BUSY; - /* fall through */ - - case STATE_DATA_BUSY: - if (!atmci_test_and_clear_pending(host, - EVENT_DATA_COMPLETE)) - break; - host->data = NULL; - atmci_set_completed(host, EVENT_DATA_COMPLETE); - status = host->data_status; - if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) { - if (status & ATMCI_DTOE) { - dev_dbg(&host->pdev->dev, - "data timeout error\n"); - data->error = -ETIMEDOUT; - } else if (status & ATMCI_DCRCE) { - dev_dbg(&host->pdev->dev, - "data CRC error\n"); - data->error = -EILSEQ; - } else { - dev_dbg(&host->pdev->dev, - "data FIFO error (status=%08x)\n", - status); - data->error = -EIO; - } + if (host->data->flags & MMC_DATA_WRITE) { + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + state = STATE_WAITING_NOTBUSY; + } else if (host->mrq->stop) { + atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); + atmci_send_stop_cmd(host, data); + state = STATE_SENDING_STOP; } else { + host->data = NULL; data->bytes_xfered = data->blocks * data->blksz; data->error = 0; - atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS); + state = STATE_END_REQUEST; } + break; - if (!data->stop) { - atmci_request_end(host, host->mrq); - goto unlock; - } + case STATE_WAITING_NOTBUSY: + /* + * We can be in the state for two reasons: a command + * requiring waiting not busy signal (stop command + * included) or a write operation. In the latest case, + * we need to send a stop command. + */ + dev_dbg(&host->pdev->dev, "FSM: not busy?\n"); + if (!atmci_test_and_clear_pending(host, + EVENT_NOTBUSY)) + break; - prev_state = state = STATE_SENDING_STOP; - if (!data->error) - atmci_send_stop_cmd(host, data); - /* fall through */ + dev_dbg(&host->pdev->dev, "set completed not busy\n"); + atmci_set_completed(host, EVENT_NOTBUSY); + + if (host->data) { + /* + * For some commands such as CMD53, even if + * there is data transfer, there is no stop + * command to send. + */ + if (host->mrq->stop) { + atmci_writel(host, ATMCI_IER, + ATMCI_CMDRDY); + atmci_send_stop_cmd(host, data); + state = STATE_SENDING_STOP; + } else { + host->data = NULL; + data->bytes_xfered = data->blocks + * data->blksz; + data->error = 0; + state = STATE_END_REQUEST; + } + } else + state = STATE_END_REQUEST; + break; case STATE_SENDING_STOP: + /* + * In this state, it is important to set host->data to + * NULL (which is tested in the waiting notbusy state) + * in order to go to the end request state instead of + * sending stop again. + */ + dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); if (!atmci_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) + EVENT_CMD_RDY)) break; + dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); host->cmd = NULL; + data->bytes_xfered = data->blocks * data->blksz; + data->error = 0; atmci_command_complete(host, mrq->stop); - atmci_request_end(host, host->mrq); - goto unlock; + if (mrq->stop->error) { + host->stop_transfer(host); + atmci_writel(host, ATMCI_IDR, + ATMCI_TXRDY | ATMCI_RXRDY + | ATMCI_DATA_ERROR_FLAGS); + state = STATE_END_REQUEST; + } else { + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); + state = STATE_WAITING_NOTBUSY; + } + host->data = NULL; + break; - case STATE_DATA_ERROR: - if (!atmci_test_and_clear_pending(host, - EVENT_XFER_COMPLETE)) - break; + case STATE_END_REQUEST: + atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY + | ATMCI_DATA_ERROR_FLAGS); + status = host->data_status; + if (unlikely(status)) { + host->stop_transfer(host); + host->data = NULL; + if (status & ATMCI_DTOE) { + data->error = -ETIMEDOUT; + } else if (status & ATMCI_DCRCE) { + data->error = -EILSEQ; + } else { + data->error = -EIO; + } + } - state = STATE_DATA_BUSY; + atmci_request_end(host, host->mrq); + state = STATE_IDLE; break; } } while (state != prev_state); host->state = state; -unlock: spin_unlock(&host->lock); } @@ -1620,9 +1783,6 @@ static void atmci_read_data_pio(struct atmel_mci *host) | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_ERROR); - tasklet_schedule(&host->tasklet); return; } } while (status & ATMCI_RXRDY); @@ -1691,9 +1851,6 @@ static void atmci_write_data_pio(struct atmel_mci *host) | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; - smp_wmb(); - atmci_set_pending(host, EVENT_DATA_ERROR); - tasklet_schedule(&host->tasklet); return; } } while (status & ATMCI_TXRDY); @@ -1711,16 +1868,6 @@ done: atmci_set_pending(host, EVENT_XFER_COMPLETE); } -static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) -{ - atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); - - host->cmd_status = status; - smp_wmb(); - atmci_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); -} - static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) { int i; @@ -1748,17 +1895,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) break; if (pending & ATMCI_DATA_ERROR_FLAGS) { + dev_dbg(&host->pdev->dev, "IRQ: data error\n"); atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS - | ATMCI_RXRDY | ATMCI_TXRDY); - pending &= atmci_readl(host, ATMCI_IMR); + | ATMCI_RXRDY | ATMCI_TXRDY + | ATMCI_ENDRX | ATMCI_ENDTX + | ATMCI_RXBUFF | ATMCI_TXBUFE); host->data_status = status; + dev_dbg(&host->pdev->dev, "set pending data error\n"); smp_wmb(); atmci_set_pending(host, EVENT_DATA_ERROR); tasklet_schedule(&host->tasklet); } if (pending & ATMCI_TXBUFE) { + dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n"); atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); /* @@ -1774,6 +1925,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_pdc_complete(host); } } else if (pending & ATMCI_ENDTX) { + dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n"); atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); if (host->data_size) { @@ -1784,6 +1936,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) } if (pending & ATMCI_RXBUFF) { + dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n"); atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); /* @@ -1799,6 +1952,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_pdc_complete(host); } } else if (pending & ATMCI_ENDRX) { + dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n"); atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); if (host->data_size) { @@ -1808,23 +1962,44 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) } } + /* + * First mci IPs, so mainly the ones having pdc, have some + * issues with the notbusy signal. You can't get it after + * data transmission if you have not sent a stop command. + * The appropriate workaround is to use the BLKE signal. + */ + if (pending & ATMCI_BLKE) { + dev_dbg(&host->pdev->dev, "IRQ: blke\n"); + atmci_writel(host, ATMCI_IDR, ATMCI_BLKE); + smp_wmb(); + dev_dbg(&host->pdev->dev, "set pending notbusy\n"); + atmci_set_pending(host, EVENT_NOTBUSY); + tasklet_schedule(&host->tasklet); + } if (pending & ATMCI_NOTBUSY) { - atmci_writel(host, ATMCI_IDR, - ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); - if (!host->data_status) - host->data_status = status; + dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); + atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); smp_wmb(); - atmci_set_pending(host, EVENT_DATA_COMPLETE); + dev_dbg(&host->pdev->dev, "set pending notbusy\n"); + atmci_set_pending(host, EVENT_NOTBUSY); tasklet_schedule(&host->tasklet); } + if (pending & ATMCI_RXRDY) atmci_read_data_pio(host); if (pending & ATMCI_TXRDY) atmci_write_data_pio(host); - if (pending & ATMCI_CMDRDY) - atmci_cmd_interrupt(host, status); + if (pending & ATMCI_CMDRDY) { + dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n"); + atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); + host->cmd_status = status; + smp_wmb(); + dev_dbg(&host->pdev->dev, "set pending cmd rdy\n"); + atmci_set_pending(host, EVENT_CMD_RDY); + tasklet_schedule(&host->tasklet); + } if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) atmci_sdio_interrupt(host, status); @@ -1877,13 +2052,26 @@ static int __init atmci_init_slot(struct atmel_mci *host, mmc->caps |= MMC_CAP_SDIO_IRQ; if (host->caps.has_highspeed) mmc->caps |= MMC_CAP_SD_HIGHSPEED; - if (slot_data->bus_width >= 4) + /* + * Without the read/write proof capability, it is strongly suggested to + * use only one bit for data to prevent fifo underruns and overruns + * which will corrupt data. + */ + if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) mmc->caps |= MMC_CAP_4_BIT_DATA; - mmc->max_segs = 64; - mmc->max_req_size = 32768 * 512; - mmc->max_blk_size = 32768; - mmc->max_blk_count = 512; + if (atmci_get_version(host) < 0x200) { + mmc->max_segs = 256; + mmc->max_blk_size = 4095; + mmc->max_blk_count = 256; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs; + } else { + mmc->max_segs = 64; + mmc->max_req_size = 32768 * 512; + mmc->max_blk_size = 32768; + mmc->max_blk_count = 512; + } /* Assume card is present initially */ set_bit(ATMCI_CARD_PRESENT, &slot->flags); @@ -2007,11 +2195,6 @@ static bool atmci_configure_dma(struct atmel_mci *host) } } -static inline unsigned int atmci_get_version(struct atmel_mci *host) -{ - return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; -} - /* * HSMCI (High Speed MCI) module is not fully compatible with MCI module. * HSMCI provides DMA support and a new config register but no more supports @@ -2032,6 +2215,9 @@ static void __init atmci_get_cap(struct atmel_mci *host) host->caps.has_highspeed = 0; host->caps.has_rwproof = 0; host->caps.has_odd_clk_div = 0; + host->caps.has_bad_data_ordering = 1; + host->caps.need_reset_after_xfer = 1; + host->caps.need_blksz_mul_4 = 1; /* keep only major version number */ switch (version & 0xf00) { @@ -2051,7 +2237,11 @@ static void __init atmci_get_cap(struct atmel_mci *host) host->caps.has_highspeed = 1; case 0x200: host->caps.has_rwproof = 1; + host->caps.need_blksz_mul_4 = 0; case 0x100: + host->caps.has_bad_data_ordering = 0; + host->caps.need_reset_after_xfer = 0; + case 0x0: break; default: host->caps.has_pdc = 0; @@ -2132,20 +2322,28 @@ static int __init atmci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); + setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); + /* We need at least one slot to succeed */ nr_slots = 0; ret = -ENODEV; if (pdata->slot[0].bus_width) { ret = atmci_init_slot(host, &pdata->slot[0], 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); - if (!ret) + if (!ret) { nr_slots++; + host->buf_size = host->slot[0]->mmc->max_req_size; + } } if (pdata->slot[1].bus_width) { ret = atmci_init_slot(host, &pdata->slot[1], 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); - if (!ret) + if (!ret) { nr_slots++; + if (host->slot[1]->mmc->max_req_size > host->buf_size) + host->buf_size = + host->slot[1]->mmc->max_req_size; + } } if (!nr_slots) { @@ -2153,6 +2351,17 @@ static int __init atmci_probe(struct platform_device *pdev) goto err_init_slot; } + if (!host->caps.has_rwproof) { + host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, + &host->buf_phys_addr, + GFP_KERNEL); + if (!host->buffer) { + ret = -ENOMEM; + dev_err(&pdev->dev, "buffer allocation failed\n"); + goto err_init_slot; + } + } + dev_info(&pdev->dev, "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", host->mapbase, irq, nr_slots); @@ -2179,6 +2388,10 @@ static int __exit atmci_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); + if (host->buffer) + dma_free_coherent(&pdev->dev, host->buf_size, + host->buffer, host->buf_phys_addr); + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { if (host->slot[i]) atmci_cleanup_slot(host->slot[i], i); diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index c1f3673ae1ef..7cf6c624bf73 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1533,4 +1533,5 @@ module_exit(davinci_mmcsd_exit); MODULE_AUTHOR("Texas Instruments India"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MMC/SD driver for Davinci MMC controller"); +MODULE_ALIAS("platform:davinci_mmc"); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index ab3fc4617107..72dc3cde646d 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -100,8 +100,6 @@ struct dw_mci_slot { int last_detect_state; }; -static struct workqueue_struct *dw_mci_card_workqueue; - #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) { @@ -407,11 +405,23 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) static int dw_mci_idmac_init(struct dw_mci *host) { struct idmac_desc *p; - int i; + int i, dma_support; /* Number of descriptors in the ring buffer */ host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); + /* Check if Hardware Configuration Register has support for DMA */ + dma_support = (mci_readl(host, HCON) >> 16) & 0x3; + + if (!dma_support || dma_support > 2) { + dev_err(&host->dev, + "Host Controller does not support IDMA Tx.\n"); + host->dma_ops = NULL; + return -ENODEV; + } + + dev_info(&host->dev, "Using internal DMA controller.\n"); + /* Forward link the descriptor list */ for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); @@ -420,6 +430,8 @@ static int dw_mci_idmac_init(struct dw_mci *host) p->des3 = host->sg_dma; p->des0 = IDMAC_DES0_ER; + mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET); + /* Mask out interrupts - get Tx & Rx complete only */ mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); @@ -617,14 +629,15 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot) u32 div; if (slot->clock != host->current_speed) { - if (host->bus_hz % slot->clock) + div = host->bus_hz / slot->clock; + if (host->bus_hz % slot->clock && host->bus_hz > slot->clock) /* * move the + 1 after the divide to prevent * over-clocking the card. */ - div = ((host->bus_hz / slot->clock) >> 1) + 1; - else - div = (host->bus_hz / slot->clock) >> 1; + div += 1; + + div = (host->bus_hz != slot->clock) ? DIV_ROUND_UP(div, 2) : 0; dev_info(&slot->mmc->class_dev, "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ" @@ -859,10 +872,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) int_mask = mci_readl(host, INTMASK); if (enb) { mci_writel(host, INTMASK, - (int_mask | (1 << SDMMC_INT_SDIO(slot->id)))); + (int_mask | SDMMC_INT_SDIO(slot->id))); } else { mci_writel(host, INTMASK, - (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id)))); + (int_mask & ~SDMMC_INT_SDIO(slot->id))); } } @@ -941,8 +954,8 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd mdelay(20); if (cmd->data) { - host->data = NULL; dw_mci_stop_dma(host); + host->data = NULL; } } } @@ -1605,7 +1618,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_CD) { mci_writel(host, RINTSTS, SDMMC_INT_CD); - queue_work(dw_mci_card_workqueue, &host->card_work); + queue_work(host->card_workqueue, &host->card_work); } /* Handle SDIO Interrupts */ @@ -1625,7 +1638,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); - set_bit(EVENT_DATA_COMPLETE, &host->pending_events); host->dma_ops->complete(host); } #endif @@ -1727,7 +1739,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) #ifdef CONFIG_MMC_DW_IDMAC ctrl = mci_readl(host, BMOD); - ctrl |= 0x01; /* Software reset of DMA */ + /* Software reset of DMA */ + ctrl |= SDMMC_IDMAC_SWRESET; mci_writel(host, BMOD, ctrl); #endif @@ -1844,7 +1857,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) * Card may have been plugged in prior to boot so we * need to run the detect tasklet */ - queue_work(dw_mci_card_workqueue, &host->card_work); + queue_work(host->card_workqueue, &host->card_work); return 0; } @@ -1875,7 +1888,6 @@ static void dw_mci_init_dma(struct dw_mci *host) /* Determine which DMA interface to use */ #ifdef CONFIG_MMC_DW_IDMAC host->dma_ops = &dw_mci_idmac_ops; - dev_info(&host->dev, "Using internal DMA controller.\n"); #endif if (!host->dma_ops) @@ -1952,10 +1964,6 @@ int dw_mci_probe(struct dw_mci *host) spin_lock_init(&host->lock); INIT_LIST_HEAD(&host->queue); - - host->dma_ops = host->pdata->dma_ops; - dw_mci_init_dma(host); - /* * Get the host data width - this assumes that HCON has been set with * the correct values. @@ -1983,10 +1991,11 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!mci_wait_reset(&host->dev, host)) { - ret = -ENODEV; - goto err_dmaunmap; - } + if (!mci_wait_reset(&host->dev, host)) + return -ENODEV; + + host->dma_ops = host->pdata->dma_ops; + dw_mci_init_dma(host); /* Clear the interrupts for the host controller */ mci_writel(host, RINTSTS, 0xFFFFFFFF); @@ -2021,9 +2030,9 @@ int dw_mci_probe(struct dw_mci *host) mci_writel(host, CLKSRC, 0); tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); - dw_mci_card_workqueue = alloc_workqueue("dw-mci-card", + host->card_workqueue = alloc_workqueue("dw-mci-card", WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); - if (!dw_mci_card_workqueue) + if (!host->card_workqueue) goto err_dmaunmap; INIT_WORK(&host->card_work, dw_mci_work_routine_card); ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host); @@ -2085,7 +2094,7 @@ err_init_slot: free_irq(host->irq, host); err_workqueue: - destroy_workqueue(dw_mci_card_workqueue); + destroy_workqueue(host->card_workqueue); err_dmaunmap: if (host->use_dma && host->dma_ops->exit) @@ -2119,7 +2128,7 @@ void dw_mci_remove(struct dw_mci *host) mci_writel(host, CLKSRC, 0); free_irq(host->irq, host); - destroy_workqueue(dw_mci_card_workqueue); + destroy_workqueue(host->card_workqueue); dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); if (host->use_dma && host->dma_ops->exit) @@ -2172,14 +2181,14 @@ int dw_mci_resume(struct dw_mci *host) if (host->vmmc) regulator_enable(host->vmmc); - if (host->dma_ops->init) - host->dma_ops->init(host); - if (!mci_wait_reset(&host->dev, host)) { ret = -ENODEV; return ret; } + if (host->use_dma && host->dma_ops->init) + host->dma_ops->init(host); + /* Restore the old value at FIFOTH register */ mci_writel(host, FIFOTH, host->fifoth_val); diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c deleted file mode 100644 index ea0f3cedef21..000000000000 --- a/drivers/mmc/host/imxmmc.c +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * linux/drivers/mmc/host/imxmmc.c - Motorola i.MX MMCI driver - * - * Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de> - * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> - * - * derived from pxamci.c by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/dma-mapping.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <asm/dma.h> -#include <asm/irq.h> -#include <asm/sizes.h> -#include <mach/mmc.h> -#include <mach/imx-dma.h> - -#include "imxmmc.h" - -#define DRIVER_NAME "imx-mmc" - -#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \ - INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \ - INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO) - -struct imxmci_host { - struct mmc_host *mmc; - spinlock_t lock; - struct resource *res; - void __iomem *base; - int irq; - imx_dmach_t dma; - volatile unsigned int imask; - unsigned int power_mode; - unsigned int present; - struct imxmmc_platform_data *pdata; - - struct mmc_request *req; - struct mmc_command *cmd; - struct mmc_data *data; - - struct timer_list timer; - struct tasklet_struct tasklet; - unsigned int status_reg; - unsigned long pending_events; - /* Next two fields are there for CPU driven transfers to overcome SDHC deficiencies */ - u16 *data_ptr; - unsigned int data_cnt; - atomic_t stuck_timeout; - - unsigned int dma_nents; - unsigned int dma_size; - unsigned int dma_dir; - int dma_allocated; - - unsigned char actual_bus_width; - - int prev_cmd_code; - - struct clk *clk; -}; - -#define IMXMCI_PEND_IRQ_b 0 -#define IMXMCI_PEND_DMA_END_b 1 -#define IMXMCI_PEND_DMA_ERR_b 2 -#define IMXMCI_PEND_WAIT_RESP_b 3 -#define IMXMCI_PEND_DMA_DATA_b 4 -#define IMXMCI_PEND_CPU_DATA_b 5 -#define IMXMCI_PEND_CARD_XCHG_b 6 -#define IMXMCI_PEND_SET_INIT_b 7 -#define IMXMCI_PEND_STARTED_b 8 - -#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) -#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) -#define IMXMCI_PEND_DMA_ERR_m (1 << IMXMCI_PEND_DMA_ERR_b) -#define IMXMCI_PEND_WAIT_RESP_m (1 << IMXMCI_PEND_WAIT_RESP_b) -#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b) -#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) -#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) -#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) -#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b) - -static void imxmci_stop_clock(struct imxmci_host *host) -{ - int i = 0; - u16 reg; - - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg & ~STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - while (i < 0x1000) { - if (!(i & 0x7f)) { - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_STOP_CLK, - host->base + MMC_REG_STR_STP_CLK); - } - - reg = readw(host->base + MMC_REG_STATUS); - if (!(reg & STATUS_CARD_BUS_CLK_RUN)) { - /* Check twice before cut */ - reg = readw(host->base + MMC_REG_STATUS); - if (!(reg & STATUS_CARD_BUS_CLK_RUN)) - return; - } - - i++; - } - dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); -} - -static int imxmci_start_clock(struct imxmci_host *host) -{ - unsigned int trials = 0; - unsigned int delay_limit = 128; - unsigned long flags; - u16 reg; - - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg & ~STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); - - clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); - - /* - * Command start of the clock, this usually succeeds in less - * then 6 delay loops, but during card detection (low clockrate) - * it takes up to 5000 delay loops and sometimes fails for the first time - */ - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); - - do { - unsigned int delay = delay_limit; - - while (delay--) { - reg = readw(host->base + MMC_REG_STATUS); - if (reg & STATUS_CARD_BUS_CLK_RUN) { - /* Check twice before cut */ - reg = readw(host->base + MMC_REG_STATUS); - if (reg & STATUS_CARD_BUS_CLK_RUN) - return 0; - } - - if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) - return 0; - } - - local_irq_save(flags); - /* - * Ensure, that request is not doubled under all possible circumstances. - * It is possible, that cock running state is missed, because some other - * IRQ or schedule delays this function execution and the clocks has - * been already stopped by other means (response processing, SDHC HW) - */ - if (!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) { - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_START_CLK, - host->base + MMC_REG_STR_STP_CLK); - } - local_irq_restore(flags); - - } while (++trials < 256); - - dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); - - return -1; -} - -static void imxmci_softreset(struct imxmci_host *host) -{ - int i; - - /* reset sequence */ - writew(0x08, host->base + MMC_REG_STR_STP_CLK); - writew(0x0D, host->base + MMC_REG_STR_STP_CLK); - - for (i = 0; i < 8; i++) - writew(0x05, host->base + MMC_REG_STR_STP_CLK); - - writew(0xff, host->base + MMC_REG_RES_TO); - writew(512, host->base + MMC_REG_BLK_LEN); - writew(1, host->base + MMC_REG_NOB); -} - -static int imxmci_busy_wait_for_status(struct imxmci_host *host, - unsigned int *pstat, unsigned int stat_mask, - int timeout, const char *where) -{ - int loops = 0; - - while (!(*pstat & stat_mask)) { - loops += 2; - if (loops >= timeout) { - dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n", - where, *pstat, stat_mask); - return -1; - } - udelay(2); - *pstat |= readw(host->base + MMC_REG_STATUS); - } - if (!loops) - return 0; - - /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */ - if (!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock >= 8000000)) - dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", - loops, where, *pstat, stat_mask); - return loops; -} - -static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data) -{ - unsigned int nob = data->blocks; - unsigned int blksz = data->blksz; - unsigned int datasz = nob * blksz; - int i; - - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - - host->data = data; - data->bytes_xfered = 0; - - writew(nob, host->base + MMC_REG_NOB); - writew(blksz, host->base + MMC_REG_BLK_LEN); - - /* - * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise. - * We are in big troubles for non-512 byte transfers according to note in the paragraph - * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least. - * The situation is even more complex in reality. The SDHC in not able to handle wll - * partial FIFO fills and reads. The length has to be rounded up to burst size multiple. - * This is required for SCR read at least. - */ - if (datasz < 512) { - host->dma_size = datasz; - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - - /* Hack to enable read SCR */ - writew(1, host->base + MMC_REG_NOB); - writew(512, host->base + MMC_REG_BLK_LEN); - } else { - host->dma_dir = DMA_TO_DEVICE; - } - - /* Convert back to virtual address */ - host->data_ptr = (u16 *)sg_virt(data->sg); - host->data_cnt = 0; - - clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); - set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); - - return; - } - - if (data->flags & MMC_DATA_READ) { - host->dma_dir = DMA_FROM_DEVICE; - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - - imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_READ); - - /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/ - CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN; - } else { - host->dma_dir = DMA_TO_DEVICE; - - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - - imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_WRITE); - - /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/ - CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN; - } - -#if 1 /* This code is there only for consistency checking and can be disabled in future */ - host->dma_size = 0; - for (i = 0; i < host->dma_nents; i++) - host->dma_size += data->sg[i].length; - - if (datasz > host->dma_size) { - dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n", - datasz, host->dma_size); - } -#endif - - host->dma_size = datasz; - - wmb(); - - set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); - clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); - - /* start DMA engine for read, write is delayed after initial response */ - if (host->dma_dir == DMA_FROM_DEVICE) - imx_dma_enable(host->dma); -} - -static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat) -{ - unsigned long flags; - u32 imask; - - WARN_ON(host->cmd != NULL); - host->cmd = cmd; - - /* Ensure, that clock are stopped else command programming and start fails */ - imxmci_stop_clock(host); - - if (cmd->flags & MMC_RSP_BUSY) - cmdat |= CMD_DAT_CONT_BUSY; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_R1: /* short CRC, OPCODE */ - case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1; - break; - case MMC_RSP_R2: /* long 136 bit + CRC */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2; - break; - case MMC_RSP_R3: /* short */ - cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3; - break; - default: - break; - } - - if (test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events)) - cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */ - - if (host->actual_bus_width == MMC_BUS_WIDTH_4) - cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; - - writew(cmd->opcode, host->base + MMC_REG_CMD); - writew(cmd->arg >> 16, host->base + MMC_REG_ARGH); - writew(cmd->arg & 0xffff, host->base + MMC_REG_ARGL); - writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); - - atomic_set(&host->stuck_timeout, 0); - set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events); - - - imask = IMXMCI_INT_MASK_DEFAULT; - imask &= ~INT_MASK_END_CMD_RES; - if (cmdat & CMD_DAT_CONT_DATA_ENABLE) { - /* imask &= ~INT_MASK_BUF_READY; */ - imask &= ~INT_MASK_DATA_TRAN; - if (cmdat & CMD_DAT_CONT_WRITE) - imask &= ~INT_MASK_WRITE_OP_DONE; - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) - imask &= ~INT_MASK_BUF_READY; - } - - spin_lock_irqsave(&host->lock, flags); - host->imask = imask; - writew(host->imask, host->base + MMC_REG_INT_MASK); - spin_unlock_irqrestore(&host->lock, flags); - - dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n", - cmd->opcode, cmd->opcode, imask); - - imxmci_start_clock(host); -} - -static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m | - IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m); - - host->imask = IMXMCI_INT_MASK_DEFAULT; - writew(host->imask, host->base + MMC_REG_INT_MASK); - - spin_unlock_irqrestore(&host->lock, flags); - - if (req && req->cmd) - host->prev_cmd_code = req->cmd->opcode; - - host->req = NULL; - host->cmd = NULL; - host->data = NULL; - mmc_request_done(host->mmc, req); -} - -static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { - imx_dma_disable(host->dma); - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents, - host->dma_dir); - } - - if (stat & STATUS_ERR_MASK) { - dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", stat); - if (stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR)) - data->error = -EILSEQ; - else if (stat & STATUS_TIME_OUT_READ) - data->error = -ETIMEDOUT; - else - data->error = -EIO; - } else { - data->bytes_xfered = host->dma_size; - } - - data_error = data->error; - - host->data = NULL; - - return data_error; -} - -static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i; - u32 a, b, c; - struct mmc_data *data = host->data; - - if (!cmd) - return 0; - - host->cmd = NULL; - - if (stat & STATUS_TIME_OUT_RESP) { - dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); - cmd->error = -ETIMEDOUT; - } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { - dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); - cmd->error = -EILSEQ; - } - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - for (i = 0; i < 4; i++) { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[i] = a << 16 | b; - } - } else { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - c = readw(host->base + MMC_REG_RES_FIFO); - cmd->resp[0] = a << 24 | b << 8 | c >> 8; - } - } - - dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n", - cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); - - if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) { - if (host->req->data->flags & MMC_DATA_WRITE) { - - /* Wait for FIFO to be empty before starting DMA write */ - - stat = readw(host->base + MMC_REG_STATUS); - if (imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FE, - 40, "imxmci_cmd_done DMA WR") < 0) { - cmd->error = -EIO; - imxmci_finish_data(host, stat); - if (host->req) - imxmci_finish_request(host, host->req); - dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n", - stat); - return 0; - } - - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - imx_dma_enable(host->dma); - } - } else { - struct mmc_request *req; - imxmci_stop_clock(host); - req = host->req; - - if (data) - imxmci_finish_data(host, stat); - - if (req) - imxmci_finish_request(host, req); - else - dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n"); - } - - return 1; -} - -static int imxmci_data_done(struct imxmci_host *host, unsigned int stat) -{ - struct mmc_data *data = host->data; - int data_error; - - if (!data) - return 0; - - data_error = imxmci_finish_data(host, stat); - - if (host->req->stop) { - imxmci_stop_clock(host); - imxmci_start_cmd(host, host->req->stop, 0); - } else { - struct mmc_request *req; - req = host->req; - if (req) - imxmci_finish_request(host, req); - else - dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n"); - } - - return 1; -} - -static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) -{ - int i; - int burst_len; - int trans_done = 0; - unsigned int stat = *pstat; - - if (host->actual_bus_width != MMC_BUS_WIDTH_4) - burst_len = 16; - else - burst_len = 64; - - /* This is unfortunately required */ - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n", - stat); - - udelay(20); /* required for clocks < 8MHz*/ - - if (host->dma_dir == DMA_FROM_DEVICE) { - imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE | - STATUS_TIME_OUT_READ, - 50, "imxmci_cpu_driven_data read"); - - while ((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) && - !(stat & STATUS_TIME_OUT_READ) && - (host->data_cnt < 512)) { - - udelay(20); /* required for clocks < 8MHz*/ - - for (i = burst_len; i >= 2 ; i -= 2) { - u16 data; - data = readw(host->base + MMC_REG_BUFFER_ACCESS); - udelay(10); /* required for clocks < 8MHz*/ - if (host->data_cnt+2 <= host->dma_size) { - *(host->data_ptr++) = data; - } else { - if (host->data_cnt < host->dma_size) - *(u8 *)(host->data_ptr) = data; - } - host->data_cnt += 2; - } - - stat = readw(host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n", - host->data_cnt, burst_len, stat); - } - - if ((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512)) - trans_done = 1; - - if (host->dma_size & 0x1ff) - stat &= ~STATUS_CRC_READ_ERR; - - if (stat & STATUS_TIME_OUT_READ) { - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n", - stat); - trans_done = -1; - } - - } else { - imxmci_busy_wait_for_status(host, &stat, - STATUS_APPL_BUFF_FE, - 20, "imxmci_cpu_driven_data write"); - - while ((stat & STATUS_APPL_BUFF_FE) && - (host->data_cnt < host->dma_size)) { - if (burst_len >= host->dma_size - host->data_cnt) { - burst_len = host->dma_size - host->data_cnt; - host->data_cnt = host->dma_size; - trans_done = 1; - } else { - host->data_cnt += burst_len; - } - - for (i = burst_len; i > 0 ; i -= 2) - writew(*(host->data_ptr++), host->base + MMC_REG_BUFFER_ACCESS); - - stat = readw(host->base + MMC_REG_STATUS); - - dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n", - burst_len, stat); - } - } - - *pstat = stat; - - return trans_done; -} - -static void imxmci_dma_irq(int dma, void *devid) -{ - struct imxmci_host *host = devid; - u32 stat = readw(host->base + MMC_REG_STATUS); - - atomic_set(&host->stuck_timeout, 0); - host->status_reg = stat; - set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); - tasklet_schedule(&host->tasklet); -} - -static irqreturn_t imxmci_irq(int irq, void *devid) -{ - struct imxmci_host *host = devid; - u32 stat = readw(host->base + MMC_REG_STATUS); - int handled = 1; - - writew(host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT, - host->base + MMC_REG_INT_MASK); - - atomic_set(&host->stuck_timeout, 0); - host->status_reg = stat; - set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); - set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); - tasklet_schedule(&host->tasklet); - - return IRQ_RETVAL(handled); -} - -static void imxmci_tasklet_fnc(unsigned long data) -{ - struct imxmci_host *host = (struct imxmci_host *)data; - u32 stat; - unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */ - int timeout = 0; - - if (atomic_read(&host->stuck_timeout) > 4) { - char *what; - timeout = 1; - stat = readw(host->base + MMC_REG_STATUS); - host->status_reg = stat; - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - what = "RESP+DMA"; - else - what = "RESP"; - else - if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) - if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events)) - what = "DATA"; - else - what = "DMA"; - else - what = "???"; - - dev_err(mmc_dev(host->mmc), - "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n", - what, stat, - readw(host->base + MMC_REG_INT_MASK)); - dev_err(mmc_dev(host->mmc), - "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n", - readw(host->base + MMC_REG_CMD_DAT_CONT), - readw(host->base + MMC_REG_BLK_LEN), - readw(host->base + MMC_REG_NOB), - CCR(host->dma)); - dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n", - host->cmd ? host->cmd->opcode : 0, - host->prev_cmd_code, - 1 << host->actual_bus_width, host->dma_size); - } - - if (!host->present || timeout) - host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ | - STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR; - - if (test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) { - clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); - - stat = readw(host->base + MMC_REG_STATUS); - /* - * This is not required in theory, but there is chance to miss some flag - * which clears automatically by mask write, FreeScale original code keeps - * stat from IRQ time so do I - */ - stat |= host->status_reg; - - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) - stat &= ~STATUS_CRC_READ_ERR; - - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { - imxmci_busy_wait_for_status(host, &stat, - STATUS_END_CMD_RESP | STATUS_ERR_MASK, - 20, "imxmci_tasklet_fnc resp (ERRATUM #4)"); - } - - if (stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) { - if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - imxmci_cmd_done(host, stat); - if (host->data && (stat & STATUS_ERR_MASK)) - imxmci_data_done(host, stat); - } - - if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) { - stat |= readw(host->base + MMC_REG_STATUS); - if (imxmci_cpu_driven_data(host, &stat)) { - if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) - imxmci_cmd_done(host, stat); - atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m, - &host->pending_events); - imxmci_data_done(host, stat); - } - } - } - - if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) && - !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { - - stat = readw(host->base + MMC_REG_STATUS); - /* Same as above */ - stat |= host->status_reg; - - if (host->dma_dir == DMA_TO_DEVICE) - data_dir_mask = STATUS_WRITE_OP_DONE; - else - data_dir_mask = STATUS_DATA_TRANS_DONE; - - if (stat & data_dir_mask) { - clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); - imxmci_data_done(host, stat); - } - } - - if (test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) { - - if (host->cmd) - imxmci_cmd_done(host, STATUS_TIME_OUT_RESP); - - if (host->data) - imxmci_data_done(host, STATUS_TIME_OUT_READ | - STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR); - - if (host->req) - imxmci_finish_request(host, host->req); - - mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - - } -} - -static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct imxmci_host *host = mmc_priv(mmc); - unsigned int cmdat; - - WARN_ON(host->req != NULL); - - host->req = req; - - cmdat = 0; - - if (req->data) { - imxmci_setup_data(host, req->data); - - cmdat |= CMD_DAT_CONT_DATA_ENABLE; - - if (req->data->flags & MMC_DATA_WRITE) - cmdat |= CMD_DAT_CONT_WRITE; - - if (req->data->flags & MMC_DATA_STREAM) - cmdat |= CMD_DAT_CONT_STREAM_BLOCK; - } - - imxmci_start_cmd(host, req->cmd, cmdat); -} - -#define CLK_RATE 19200000 - -static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct imxmci_host *host = mmc_priv(mmc); - int prescaler; - - if (ios->bus_width == MMC_BUS_WIDTH_4) { - host->actual_bus_width = MMC_BUS_WIDTH_4; - imx_gpio_mode(PB11_PF_SD_DAT3); - BLR(host->dma) = 0; /* burst 64 byte read/write */ - } else { - host->actual_bus_width = MMC_BUS_WIDTH_1; - imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); - BLR(host->dma) = 16; /* burst 16 byte read/write */ - } - - if (host->power_mode != ios->power_mode) { - switch (ios->power_mode) { - case MMC_POWER_OFF: - break; - case MMC_POWER_UP: - set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); - break; - case MMC_POWER_ON: - break; - } - host->power_mode = ios->power_mode; - } - - if (ios->clock) { - unsigned int clk; - u16 reg; - - /* The prescaler is 5 for PERCLK2 equal to 96MHz - * then 96MHz / 5 = 19.2 MHz - */ - clk = clk_get_rate(host->clk); - prescaler = (clk + (CLK_RATE * 7) / 8) / CLK_RATE; - switch (prescaler) { - case 0: - case 1: prescaler = 0; - break; - case 2: prescaler = 1; - break; - case 3: prescaler = 2; - break; - case 4: prescaler = 4; - break; - default: - case 5: prescaler = 5; - break; - } - - dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n", - clk, prescaler); - - for (clk = 0; clk < 8; clk++) { - int x; - x = CLK_RATE / (1 << clk); - if (x <= ios->clock) - break; - } - - /* enable controller */ - reg = readw(host->base + MMC_REG_STR_STP_CLK); - writew(reg | STR_STP_CLK_ENABLE, - host->base + MMC_REG_STR_STP_CLK); - - imxmci_stop_clock(host); - writew((prescaler << 3) | clk, host->base + MMC_REG_CLK_RATE); - /* - * Under my understanding, clock should not be started there, because it would - * initiate SDHC sequencer and send last or random command into card - */ - /* imxmci_start_clock(host); */ - - dev_dbg(mmc_dev(host->mmc), - "MMC_CLK_RATE: 0x%08x\n", - readw(host->base + MMC_REG_CLK_RATE)); - } else { - imxmci_stop_clock(host); - } -} - -static int imxmci_get_ro(struct mmc_host *mmc) -{ - struct imxmci_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_ro) - return !!host->pdata->get_ro(mmc_dev(mmc)); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - - -static const struct mmc_host_ops imxmci_ops = { - .request = imxmci_request, - .set_ios = imxmci_set_ios, - .get_ro = imxmci_get_ro, -}; - -static void imxmci_check_status(unsigned long data) -{ - struct imxmci_host *host = (struct imxmci_host *)data; - - if (host->pdata && host->pdata->card_present && - host->pdata->card_present(mmc_dev(host->mmc)) != host->present) { - host->present ^= 1; - dev_info(mmc_dev(host->mmc), "card %s\n", - host->present ? "inserted" : "removed"); - - set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) || - test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { - atomic_inc(&host->stuck_timeout); - if (atomic_read(&host->stuck_timeout) > 4) - tasklet_schedule(&host->tasklet); - } else { - atomic_set(&host->stuck_timeout, 0); - - } - - mod_timer(&host->timer, jiffies + (HZ>>1)); -} - -static int __init imxmci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct imxmci_host *host = NULL; - struct resource *r; - int ret = 0, irq; - u16 rev_no; - - pr_info("i.MX mmc driver\n"); - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!r || irq < 0) - return -ENXIO; - - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (!r) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - mmc->ops = &imxmci_ops; - mmc->f_min = 150000; - mmc->f_max = CLK_RATE/2; - mmc->ocr_avail = MMC_VDD_32_33; - mmc->caps = MMC_CAP_4_BIT_DATA; - - /* MMC core transfer sizes tunable parameters */ - mmc->max_segs = 64; - mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */ - mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */ - mmc->max_blk_size = 2048; - mmc->max_blk_count = 65535; - - host = mmc_priv(mmc); - host->base = ioremap(r->start, resource_size(r)); - if (!host->base) { - ret = -ENOMEM; - goto out; - } - - host->mmc = mmc; - host->dma_allocated = 0; - host->pdata = pdev->dev.platform_data; - if (!host->pdata) - dev_warn(&pdev->dev, "No platform data provided!\n"); - - spin_lock_init(&host->lock); - host->res = r; - host->irq = irq; - - host->clk = clk_get(&pdev->dev, "perclk2"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto out; - } - clk_enable(host->clk); - - imx_gpio_mode(PB8_PF_SD_DAT0); - imx_gpio_mode(PB9_PF_SD_DAT1); - imx_gpio_mode(PB10_PF_SD_DAT2); - /* Configured as GPIO with pull-up to ensure right MCC card mode */ - /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */ - imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); - /* imx_gpio_mode(PB11_PF_SD_DAT3); */ - imx_gpio_mode(PB12_PF_SD_CLK); - imx_gpio_mode(PB13_PF_SD_CMD); - - imxmci_softreset(host); - - rev_no = readw(host->base + MMC_REG_REV_NO); - if (rev_no != 0x390) { - dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", - readw(host->base + MMC_REG_REV_NO)); - goto out; - } - - /* recommended in data sheet */ - writew(0x2db4, host->base + MMC_REG_READ_TO); - - host->imask = IMXMCI_INT_MASK_DEFAULT; - writew(host->imask, host->base + MMC_REG_INT_MASK); - - host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); - if(host->dma < 0) { - dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n"); - ret = -EBUSY; - goto out; - } - host->dma_allocated = 1; - imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host); - RSSR(host->dma) = DMA_REQ_SDHC; - - tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host); - host->status_reg=0; - host->pending_events=0; - - ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host); - if (ret) - goto out; - - if (host->pdata && host->pdata->card_present) - host->present = host->pdata->card_present(mmc_dev(mmc)); - else /* if there is no way to detect assume that card is present */ - host->present = 1; - - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = imxmci_check_status; - add_timer(&host->timer); - mod_timer(&host->timer, jiffies + (HZ >> 1)); - - platform_set_drvdata(pdev, mmc); - - mmc_add_host(mmc); - - return 0; - -out: - if (host) { - if (host->dma_allocated) { - imx_dma_free(host->dma); - host->dma_allocated = 0; - } - if (host->clk) { - clk_disable(host->clk); - clk_put(host->clk); - } - if (host->base) - iounmap(host->base); - } - if (mmc) - mmc_free_host(mmc); - release_mem_region(r->start, resource_size(r)); - return ret; -} - -static int __exit imxmci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (mmc) { - struct imxmci_host *host = mmc_priv(mmc); - - tasklet_disable(&host->tasklet); - - del_timer_sync(&host->timer); - mmc_remove_host(mmc); - - free_irq(host->irq, host); - iounmap(host->base); - if (host->dma_allocated) { - imx_dma_free(host->dma); - host->dma_allocated = 0; - } - - tasklet_kill(&host->tasklet); - - clk_disable(host->clk); - clk_put(host->clk); - - release_mem_region(host->res->start, resource_size(host->res)); - - mmc_free_host(mmc); - } - return 0; -} - -#ifdef CONFIG_PM -static int imxmci_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int imxmci_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - struct imxmci_host *host; - int ret = 0; - - if (mmc) { - host = mmc_priv(mmc); - if (host) - set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); - ret = mmc_resume_host(mmc); - } - - return ret; -} -#else -#define imxmci_suspend NULL -#define imxmci_resume NULL -#endif /* CONFIG_PM */ - -static struct platform_driver imxmci_driver = { - .remove = __exit_p(imxmci_remove), - .suspend = imxmci_suspend, - .resume = imxmci_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - } -}; - -static int __init imxmci_init(void) -{ - return platform_driver_probe(&imxmci_driver, imxmci_probe); -} - -static void __exit imxmci_exit(void) -{ - platform_driver_unregister(&imxmci_driver); -} - -module_init(imxmci_init); -module_exit(imxmci_exit); - -MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); -MODULE_AUTHOR("Sascha Hauer, Pengutronix"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-mmc"); diff --git a/drivers/mmc/host/imxmmc.h b/drivers/mmc/host/imxmmc.h deleted file mode 100644 index 09d5d4ee3a77..000000000000 --- a/drivers/mmc/host/imxmmc.h +++ /dev/null @@ -1,64 +0,0 @@ -#define MMC_REG_STR_STP_CLK 0x00 -#define MMC_REG_STATUS 0x04 -#define MMC_REG_CLK_RATE 0x08 -#define MMC_REG_CMD_DAT_CONT 0x0C -#define MMC_REG_RES_TO 0x10 -#define MMC_REG_READ_TO 0x14 -#define MMC_REG_BLK_LEN 0x18 -#define MMC_REG_NOB 0x1C -#define MMC_REG_REV_NO 0x20 -#define MMC_REG_INT_MASK 0x24 -#define MMC_REG_CMD 0x28 -#define MMC_REG_ARGH 0x2C -#define MMC_REG_ARGL 0x30 -#define MMC_REG_RES_FIFO 0x34 -#define MMC_REG_BUFFER_ACCESS 0x38 - -#define STR_STP_CLK_IPG_CLK_GATE_DIS (1<<15) -#define STR_STP_CLK_IPG_PERCLK_GATE_DIS (1<<14) -#define STR_STP_CLK_ENDIAN (1<<5) -#define STR_STP_CLK_RESET (1<<3) -#define STR_STP_CLK_ENABLE (1<<2) -#define STR_STP_CLK_START_CLK (1<<1) -#define STR_STP_CLK_STOP_CLK (1<<0) -#define STATUS_CARD_PRESENCE (1<<15) -#define STATUS_SDIO_INT_ACTIVE (1<<14) -#define STATUS_END_CMD_RESP (1<<13) -#define STATUS_WRITE_OP_DONE (1<<12) -#define STATUS_DATA_TRANS_DONE (1<<11) -#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10) -#define STATUS_CARD_BUS_CLK_RUN (1<<8) -#define STATUS_APPL_BUFF_FF (1<<7) -#define STATUS_APPL_BUFF_FE (1<<6) -#define STATUS_RESP_CRC_ERR (1<<5) -#define STATUS_CRC_READ_ERR (1<<3) -#define STATUS_CRC_WRITE_ERR (1<<2) -#define STATUS_TIME_OUT_RESP (1<<1) -#define STATUS_TIME_OUT_READ (1<<0) -#define STATUS_ERR_MASK 0x2f -#define CLK_RATE_PRESCALER(x) ((x) & 0x7) -#define CLK_RATE_CLK_RATE(x) (((x) & 0x7) << 3) -#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12) -#define CMD_DAT_CONT_STOP_READWAIT (1<<11) -#define CMD_DAT_CONT_START_READWAIT (1<<10) -#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8) -#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8) -#define CMD_DAT_CONT_INIT (1<<7) -#define CMD_DAT_CONT_BUSY (1<<6) -#define CMD_DAT_CONT_STREAM_BLOCK (1<<5) -#define CMD_DAT_CONT_WRITE (1<<4) -#define CMD_DAT_CONT_DATA_ENABLE (1<<3) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5) -#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6) -#define INT_MASK_AUTO_CARD_DETECT (1<<6) -#define INT_MASK_DAT0_EN (1<<5) -#define INT_MASK_SDIO (1<<4) -#define INT_MASK_BUF_READY (1<<3) -#define INT_MASK_END_CMD_RES (1<<2) -#define INT_MASK_WRITE_OP_DONE (1<<1) -#define INT_MASK_DATA_TRAN (1<<0) -#define INT_ALL (0x7f) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 032b84791a16..50ff19a62368 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -15,6 +15,7 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/highmem.h> @@ -25,6 +26,7 @@ #include <linux/clk.h> #include <linux/scatterlist.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/regulator/consumer.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> @@ -94,6 +96,17 @@ static struct variant_data variant_u300 = { .signal_direction = true, }; +static struct variant_data variant_nomadik = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .clkreg = MCI_CLK_ENABLE, + .datalength_bits = 24, + .sdio = true, + .st_clkdiv = true, + .pwrreg_powerup = MCI_PWR_ON, + .signal_direction = true, +}; + static struct variant_data variant_ux500 = { .fifosize = 30 * 4, .fifohalfsize = 8 * 4, @@ -1196,21 +1209,77 @@ static const struct mmc_host_ops mmci_ops = { .get_cd = mmci_get_cd, }; +#ifdef CONFIG_OF +static void mmci_dt_populate_generic_pdata(struct device_node *np, + struct mmci_platform_data *pdata) +{ + int bus_width = 0; + + pdata->gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); + pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); + + if (of_get_property(np, "cd-inverted", NULL)) + pdata->cd_invert = true; + else + pdata->cd_invert = false; + + of_property_read_u32(np, "max-frequency", &pdata->f_max); + if (!pdata->f_max) + pr_warn("%s has no 'max-frequency' property\n", np->full_name); + + if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) + pdata->capabilities |= MMC_CAP_MMC_HIGHSPEED; + if (of_get_property(np, "mmc-cap-sd-highspeed", NULL)) + pdata->capabilities |= MMC_CAP_SD_HIGHSPEED; + + of_property_read_u32(np, "bus-width", &bus_width); + switch (bus_width) { + case 0 : + /* No bus-width supplied. */ + break; + case 4 : + pdata->capabilities |= MMC_CAP_4_BIT_DATA; + break; + case 8 : + pdata->capabilities |= MMC_CAP_8_BIT_DATA; + break; + default : + pr_warn("%s: Unsupported bus width\n", np->full_name); + } +} +#else +static void mmci_dt_populate_generic_pdata(struct device_node *np, + struct mmci_platform_data *pdata) +{ + return; +} +#endif + static int __devinit mmci_probe(struct amba_device *dev, const struct amba_id *id) { struct mmci_platform_data *plat = dev->dev.platform_data; + struct device_node *np = dev->dev.of_node; struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; int ret; - /* must have platform data */ + /* Must have platform data or Device Tree. */ + if (!plat && !np) { + dev_err(&dev->dev, "No plat data or DT found\n"); + return -EINVAL; + } + if (!plat) { - ret = -EINVAL; - goto out; + plat = devm_kzalloc(&dev->dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; } + if (np) + mmci_dt_populate_generic_pdata(np, plat); + ret = amba_request_regions(dev, DRIVER_NAME); if (ret) goto out; @@ -1356,6 +1425,10 @@ static int __devinit mmci_probe(struct amba_device *dev, writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); + if (plat->gpio_cd == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_gpio_cd; + } if (gpio_is_valid(plat->gpio_cd)) { ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); if (ret == 0) @@ -1379,6 +1452,10 @@ static int __devinit mmci_probe(struct amba_device *dev, if (ret >= 0) host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } + if (plat->gpio_wp == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_gpio_wp; + } if (gpio_is_valid(plat->gpio_wp)) { ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); if (ret == 0) @@ -1397,7 +1474,7 @@ static int __devinit mmci_probe(struct amba_device *dev, if (ret) goto unmap; - if (dev->irq[1] == NO_IRQ || !dev->irq[1]) + if (!dev->irq[1]) host->singleirq = true; else { ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, @@ -1569,6 +1646,11 @@ static struct amba_id mmci_ids[] = { .data = &variant_u300, }, { + .id = 0x10180180, + .mask = 0xf0ffffff, + .data = &variant_nomadik, + }, + { .id = 0x00280180, .mask = 0x00ffffff, .data = &variant_u300, diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index eeb8cd125b0c..a61cb5fca22d 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -19,6 +19,7 @@ #include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/irq.h> +#include <linux/clk.h> #include <linux/gpio.h> #include <linux/mmc/host.h> @@ -51,6 +52,7 @@ struct mvsd_host { struct device *dev; struct resource *res; int irq; + struct clk *clk; int gpio_card_detect; int gpio_write_protect; }; @@ -770,6 +772,13 @@ static int __init mvsd_probe(struct platform_device *pdev) } else host->irq = irq; + /* Not all platforms can gate the clock, so it is not + an error if the clock does not exists. */ + host->clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(host->clk)) { + clk_prepare_enable(host->clk); + } + if (mvsd_data->gpio_card_detect) { ret = gpio_request(mvsd_data->gpio_card_detect, DRIVER_NAME " cd"); @@ -830,6 +839,10 @@ out: if (r) release_resource(r); if (mmc) + if (!IS_ERR_OR_NULL(host->clk)) { + clk_disable_unprepare(host->clk); + clk_put(host->clk); + } mmc_free_host(mmc); return ret; @@ -854,6 +867,11 @@ static int __exit mvsd_remove(struct platform_device *pdev) mvsd_power_down(host); iounmap(host->base); release_resource(host->res); + + if (!IS_ERR(host->clk)) { + clk_disable_unprepare(host->clk); + clk_put(host->clk); + } mmc_free_host(mmc); } platform_set_drvdata(pdev, NULL); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index b2058b432320..28ed52d58f7f 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -136,7 +136,8 @@ struct mxcmci_host { u16 rev_no; unsigned int cmdat; - struct clk *clk; + struct clk *clk_ipg; + struct clk *clk_per; int clock; @@ -672,7 +673,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) { unsigned int divider; int prescaler = 0; - unsigned int clk_in = clk_get_rate(host->clk); + unsigned int clk_in = clk_get_rate(host->clk_per); while (prescaler <= 0x800) { for (divider = 1; divider <= 0xF; divider++) { @@ -900,12 +901,20 @@ static int mxcmci_probe(struct platform_device *pdev) host->res = r; host->irq = irq; - host->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); + host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(host->clk_ipg)) { + ret = PTR_ERR(host->clk_ipg); goto out_iounmap; } - clk_enable(host->clk); + + host->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(host->clk_per)) { + ret = PTR_ERR(host->clk_per); + goto out_iounmap; + } + + clk_prepare_enable(host->clk_per); + clk_prepare_enable(host->clk_ipg); mxcmci_softreset(host); @@ -917,8 +926,8 @@ static int mxcmci_probe(struct platform_device *pdev) goto out_clk_put; } - mmc->f_min = clk_get_rate(host->clk) >> 16; - mmc->f_max = clk_get_rate(host->clk) >> 1; + mmc->f_min = clk_get_rate(host->clk_per) >> 16; + mmc->f_max = clk_get_rate(host->clk_per) >> 1; /* recommended in data sheet */ writew(0x2db4, host->base + MMC_REG_READ_TO); @@ -967,8 +976,8 @@ out_free_dma: if (host->dma) dma_release_channel(host->dma); out_clk_put: - clk_disable(host->clk); - clk_put(host->clk); + clk_disable_unprepare(host->clk_per); + clk_disable_unprepare(host->clk_ipg); out_iounmap: iounmap(host->base); out_free: @@ -999,8 +1008,8 @@ static int mxcmci_remove(struct platform_device *pdev) if (host->dma) dma_release_channel(host->dma); - clk_disable(host->clk); - clk_put(host->clk); + clk_disable_unprepare(host->clk_per); + clk_disable_unprepare(host->clk_ipg); release_mem_region(host->res->start, resource_size(host->res)); @@ -1018,7 +1027,8 @@ static int mxcmci_suspend(struct device *dev) if (mmc) ret = mmc_suspend_host(mmc); - clk_disable(host->clk); + clk_disable_unprepare(host->clk_per); + clk_disable_unprepare(host->clk_ipg); return ret; } @@ -1029,7 +1039,8 @@ static int mxcmci_resume(struct device *dev) struct mxcmci_host *host = mmc_priv(mmc); int ret = 0; - clk_enable(host->clk); + clk_prepare_enable(host->clk_per); + clk_prepare_enable(host->clk_ipg); if (mmc) ret = mmc_resume_host(mmc); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index e3f5af96ab87..a51f9309ffbb 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -23,6 +23,9 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/ioport.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -39,18 +42,16 @@ #include <linux/regulator/consumer.h> #include <linux/module.h> #include <linux/fsl/mxs-dma.h> - -#include <mach/mxs.h> -#include <mach/common.h> -#include <mach/mmc.h> +#include <linux/pinctrl/consumer.h> +#include <linux/stmp_device.h> +#include <linux/mmc/mxs-mmc.h> #define DRIVER_NAME "mxs-mmc" /* card detect polling timeout */ #define MXS_MMC_DETECT_TIMEOUT (HZ/2) -#define SSP_VERSION_LATEST 4 -#define ssp_is_old() (host->version < SSP_VERSION_LATEST) +#define ssp_is_old(host) ((host)->devid == IMX23_MMC) /* SSP registers */ #define HW_SSP_CTRL0 0x000 @@ -85,14 +86,14 @@ #define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4) #define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0) #define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf) -#define HW_SSP_TIMING (ssp_is_old() ? 0x050 : 0x070) +#define HW_SSP_TIMING(h) (ssp_is_old(h) ? 0x050 : 0x070) #define BP_SSP_TIMING_TIMEOUT (16) #define BM_SSP_TIMING_TIMEOUT (0xffff << 16) #define BP_SSP_TIMING_CLOCK_DIVIDE (8) #define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8) #define BP_SSP_TIMING_CLOCK_RATE (0) #define BM_SSP_TIMING_CLOCK_RATE (0xff) -#define HW_SSP_CTRL1 (ssp_is_old() ? 0x060 : 0x080) +#define HW_SSP_CTRL1(h) (ssp_is_old(h) ? 0x060 : 0x080) #define BM_SSP_CTRL1_SDIO_IRQ (1 << 31) #define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30) #define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29) @@ -115,15 +116,13 @@ #define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4) #define BP_SSP_CTRL1_SSP_MODE (0) #define BM_SSP_CTRL1_SSP_MODE (0xf) -#define HW_SSP_SDRESP0 (ssp_is_old() ? 0x080 : 0x0a0) -#define HW_SSP_SDRESP1 (ssp_is_old() ? 0x090 : 0x0b0) -#define HW_SSP_SDRESP2 (ssp_is_old() ? 0x0a0 : 0x0c0) -#define HW_SSP_SDRESP3 (ssp_is_old() ? 0x0b0 : 0x0d0) -#define HW_SSP_STATUS (ssp_is_old() ? 0x0c0 : 0x100) +#define HW_SSP_SDRESP0(h) (ssp_is_old(h) ? 0x080 : 0x0a0) +#define HW_SSP_SDRESP1(h) (ssp_is_old(h) ? 0x090 : 0x0b0) +#define HW_SSP_SDRESP2(h) (ssp_is_old(h) ? 0x0a0 : 0x0c0) +#define HW_SSP_SDRESP3(h) (ssp_is_old(h) ? 0x0b0 : 0x0d0) +#define HW_SSP_STATUS(h) (ssp_is_old(h) ? 0x0c0 : 0x100) #define BM_SSP_STATUS_CARD_DETECT (1 << 28) #define BM_SSP_STATUS_SDIO_IRQ (1 << 17) -#define HW_SSP_VERSION (cpu_is_mx23() ? 0x110 : 0x130) -#define BP_SSP_VERSION_MAJOR (24) #define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field) @@ -138,6 +137,11 @@ #define SSP_PIO_NUM 3 +enum mxs_mmc_id { + IMX23_MMC, + IMX28_MMC, +}; + struct mxs_mmc_host { struct mmc_host *mmc; struct mmc_request *mrq; @@ -145,9 +149,7 @@ struct mxs_mmc_host { struct mmc_data *data; void __iomem *base; - int irq; - struct resource *res; - struct resource *dma_res; + int dma_channel; struct clk *clk; unsigned int clk_rate; @@ -157,32 +159,35 @@ struct mxs_mmc_host { enum dma_transfer_direction slave_dirn; u32 ssp_pio_words[SSP_PIO_NUM]; - unsigned int version; + enum mxs_mmc_id devid; unsigned char bus_width; spinlock_t lock; int sdio_irq_en; + int wp_gpio; + bool wp_inverted; }; static int mxs_mmc_get_ro(struct mmc_host *mmc) { struct mxs_mmc_host *host = mmc_priv(mmc); - struct mxs_mmc_platform_data *pdata = - mmc_dev(host->mmc)->platform_data; + int ret; - if (!pdata) - return -EFAULT; - - if (!gpio_is_valid(pdata->wp_gpio)) + if (!gpio_is_valid(host->wp_gpio)) return -EINVAL; - return gpio_get_value(pdata->wp_gpio); + ret = gpio_get_value(host->wp_gpio); + + if (host->wp_inverted) + ret = !ret; + + return ret; } static int mxs_mmc_get_cd(struct mmc_host *mmc) { struct mxs_mmc_host *host = mmc_priv(mmc); - return !(readl(host->base + HW_SSP_STATUS) & + return !(readl(host->base + HW_SSP_STATUS(host)) & BM_SSP_STATUS_CARD_DETECT); } @@ -190,7 +195,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) { u32 ctrl0, ctrl1; - mxs_reset_block(host->base); + stmp_reset_block(host->base); ctrl0 = BM_SSP_CTRL0_IGNORE_CRC; ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) | @@ -206,7 +211,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) writel(BF_SSP(0xffff, TIMING_TIMEOUT) | BF_SSP(2, TIMING_CLOCK_DIVIDE) | BF_SSP(0, TIMING_CLOCK_RATE), - host->base + HW_SSP_TIMING); + host->base + HW_SSP_TIMING(host)); if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; @@ -214,7 +219,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) } writel(ctrl0, host->base + HW_SSP_CTRL0); - writel(ctrl1, host->base + HW_SSP_CTRL1); + writel(ctrl1, host->base + HW_SSP_CTRL1(host)); } static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, @@ -228,12 +233,12 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host) if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { if (mmc_resp_type(cmd) & MMC_RSP_136) { - cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0); - cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1); - cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2); - cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3); + cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0(host)); + cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1(host)); + cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2(host)); + cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3(host)); } else { - cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0); + cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0(host)); } } @@ -276,9 +281,9 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) spin_lock(&host->lock); - stat = readl(host->base + HW_SSP_CTRL1); + stat = readl(host->base + HW_SSP_CTRL1(host)); writel(stat & MXS_MMC_IRQ_BITS, - host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); + host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_CLR); if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); @@ -484,7 +489,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) blocks = 1; /* xfer count, block size and count need to be set differently */ - if (ssp_is_old()) { + if (ssp_is_old(host)) { ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT); cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) | BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); @@ -508,10 +513,10 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) /* set the timeout count */ timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns); - val = readl(host->base + HW_SSP_TIMING); + val = readl(host->base + HW_SSP_TIMING(host)); val &= ~(BM_SSP_TIMING_TIMEOUT); val |= BF_SSP(timeout, TIMING_TIMEOUT); - writel(val, host->base + HW_SSP_TIMING); + writel(val, host->base + HW_SSP_TIMING(host)); /* pio */ host->ssp_pio_words[0] = ctrl0; @@ -597,11 +602,11 @@ static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate) ssp_sck = ssp_clk / clock_divide / (1 + clock_rate); - val = readl(host->base + HW_SSP_TIMING); + val = readl(host->base + HW_SSP_TIMING(host)); val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE); val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE); - writel(val, host->base + HW_SSP_TIMING); + writel(val, host->base + HW_SSP_TIMING(host)); host->clk_rate = ssp_sck; @@ -636,18 +641,19 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) if (enable) { writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, - host->base + HW_SSP_CTRL0 + MXS_SET_ADDR); + host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); writel(BM_SSP_CTRL1_SDIO_IRQ_EN, - host->base + HW_SSP_CTRL1 + MXS_SET_ADDR); + host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_SET); - if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ) + if (readl(host->base + HW_SSP_STATUS(host)) & + BM_SSP_STATUS_SDIO_IRQ) mmc_signal_sdio_irq(host->mmc); } else { writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, - host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR); + host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); writel(BM_SSP_CTRL1_SDIO_IRQ_EN, - host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); + host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_CLR); } spin_unlock_irqrestore(&host->lock, flags); @@ -668,7 +674,7 @@ static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param) if (!mxs_dma_is_apbh(chan)) return false; - if (chan->chan_id != host->dma_res->start) + if (chan->chan_id != host->dma_channel) return false; chan->private = &host->dma_data; @@ -676,53 +682,100 @@ static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param) return true; } +static struct platform_device_id mxs_mmc_ids[] = { + { + .name = "imx23-mmc", + .driver_data = IMX23_MMC, + }, { + .name = "imx28-mmc", + .driver_data = IMX28_MMC, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, mxs_mmc_ids); + +static const struct of_device_id mxs_mmc_dt_ids[] = { + { .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_MMC, }, + { .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_MMC, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids); + static int mxs_mmc_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(mxs_mmc_dt_ids, &pdev->dev); + struct device_node *np = pdev->dev.of_node; struct mxs_mmc_host *host; struct mmc_host *mmc; - struct resource *iores, *dmares, *r; + struct resource *iores, *dmares; struct mxs_mmc_platform_data *pdata; + struct pinctrl *pinctrl; int ret = 0, irq_err, irq_dma; dma_cap_mask_t mask; + struct regulator *reg_vmmc; + enum of_gpio_flags flags; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); irq_err = platform_get_irq(pdev, 0); irq_dma = platform_get_irq(pdev, 1); - if (!iores || !dmares || irq_err < 0 || irq_dma < 0) + if (!iores || irq_err < 0 || irq_dma < 0) return -EINVAL; - r = request_mem_region(iores->start, resource_size(iores), pdev->name); - if (!r) - return -EBUSY; - mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out_release_mem; - } + if (!mmc) + return -ENOMEM; host = mmc_priv(mmc); - host->base = ioremap(r->start, resource_size(r)); + host->base = devm_request_and_ioremap(&pdev->dev, iores); if (!host->base) { - ret = -ENOMEM; + ret = -EADDRNOTAVAIL; goto out_mmc_free; } - /* only major verion does matter */ - host->version = readl(host->base + HW_SSP_VERSION) >> - BP_SSP_VERSION_MAJOR; + if (np) { + host->devid = (enum mxs_mmc_id) of_id->data; + /* + * TODO: This is a temporary solution and should be changed + * to use generic DMA binding later when the helpers get in. + */ + ret = of_property_read_u32(np, "fsl,ssp-dma-channel", + &host->dma_channel); + if (ret) { + dev_err(mmc_dev(host->mmc), + "failed to get dma channel\n"); + goto out_mmc_free; + } + } else { + host->devid = pdev->id_entry->driver_data; + host->dma_channel = dmares->start; + } host->mmc = mmc; - host->res = r; - host->dma_res = dmares; - host->irq = irq_err; host->sdio_irq_en = 0; + reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc"); + if (!IS_ERR(reg_vmmc)) { + ret = regulator_enable(reg_vmmc); + if (ret) { + dev_err(&pdev->dev, + "Failed to enable vmmc regulator: %d\n", ret); + goto out_mmc_free; + } + } + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto out_mmc_free; + } + host->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); - goto out_iounmap; + goto out_mmc_free; } clk_prepare_enable(host->clk); @@ -744,11 +797,23 @@ static int mxs_mmc_probe(struct platform_device *pdev) MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; pdata = mmc_dev(host->mmc)->platform_data; - if (pdata) { + if (!pdata) { + u32 bus_width = 0; + of_property_read_u32(np, "bus-width", &bus_width); + if (bus_width == 4) + mmc->caps |= MMC_CAP_4_BIT_DATA; + else if (bus_width == 8) + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, + &flags); + if (flags & OF_GPIO_ACTIVE_LOW) + host->wp_inverted = 1; + } else { if (pdata->flags & SLOTF_8_BIT_CAPABLE) mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; if (pdata->flags & SLOTF_4_BIT_CAPABLE) mmc->caps |= MMC_CAP_4_BIT_DATA; + host->wp_gpio = pdata->wp_gpio; } mmc->f_min = 400000; @@ -757,13 +822,14 @@ static int mxs_mmc_probe(struct platform_device *pdev) mmc->max_segs = 52; mmc->max_blk_size = 1 << 0xf; - mmc->max_blk_count = (ssp_is_old()) ? 0xff : 0xffffff; - mmc->max_req_size = (ssp_is_old()) ? 0xffff : 0xffffffff; + mmc->max_blk_count = (ssp_is_old(host)) ? 0xff : 0xffffff; + mmc->max_req_size = (ssp_is_old(host)) ? 0xffff : 0xffffffff; mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev); platform_set_drvdata(pdev, mmc); - ret = request_irq(host->irq, mxs_mmc_irq_handler, 0, DRIVER_NAME, host); + ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, + DRIVER_NAME, host); if (ret) goto out_free_dma; @@ -771,26 +837,20 @@ static int mxs_mmc_probe(struct platform_device *pdev) ret = mmc_add_host(mmc); if (ret) - goto out_free_irq; + goto out_free_dma; dev_info(mmc_dev(host->mmc), "initialized\n"); return 0; -out_free_irq: - free_irq(host->irq, host); out_free_dma: if (host->dmach) dma_release_channel(host->dmach); out_clk_put: clk_disable_unprepare(host->clk); clk_put(host->clk); -out_iounmap: - iounmap(host->base); out_mmc_free: mmc_free_host(mmc); -out_release_mem: - release_mem_region(iores->start, resource_size(iores)); return ret; } @@ -798,12 +858,9 @@ static int mxs_mmc_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct mxs_mmc_host *host = mmc_priv(mmc); - struct resource *res = host->res; mmc_remove_host(mmc); - free_irq(host->irq, host); - platform_set_drvdata(pdev, NULL); if (host->dmach) @@ -812,12 +869,8 @@ static int mxs_mmc_remove(struct platform_device *pdev) clk_disable_unprepare(host->clk); clk_put(host->clk); - iounmap(host->base); - mmc_free_host(mmc); - release_mem_region(res->start, resource_size(res)); - return 0; } @@ -857,12 +910,14 @@ static const struct dev_pm_ops mxs_mmc_pm_ops = { static struct platform_driver mxs_mmc_driver = { .probe = mxs_mmc_probe, .remove = mxs_mmc_remove, + .id_table = mxs_mmc_ids, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &mxs_mmc_pm_ops, #endif + .of_match_table = mxs_mmc_dt_ids, }, }; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 887c0e598cf3..3e8dcf8d2e05 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -169,11 +169,11 @@ struct mmc_omap_host { struct timer_list clk_timer; spinlock_t clk_lock; /* for changing enabled state */ unsigned int fclk_enabled:1; + struct workqueue_struct *mmc_omap_wq; struct omap_mmc_platform_data *pdata; }; -static struct workqueue_struct *mmc_omap_wq; static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot) { @@ -291,7 +291,7 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) host->next_slot = new_slot; host->mmc = new_slot->mmc; spin_unlock_irqrestore(&host->slot_lock, flags); - queue_work(mmc_omap_wq, &host->slot_release_work); + queue_work(host->mmc_omap_wq, &host->slot_release_work); return; } @@ -459,7 +459,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) } host->stop_data = data; - queue_work(mmc_omap_wq, &host->send_stop_work); + queue_work(host->mmc_omap_wq, &host->send_stop_work); } static void @@ -639,7 +639,7 @@ mmc_omap_cmd_timer(unsigned long data) OMAP_MMC_WRITE(host, IE, 0); disable_irq(host->irq); host->abort = 1; - queue_work(mmc_omap_wq, &host->cmd_abort_work); + queue_work(host->mmc_omap_wq, &host->cmd_abort_work); } spin_unlock_irqrestore(&host->slot_lock, flags); } @@ -828,7 +828,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) host->abort = 1; OMAP_MMC_WRITE(host, IE, 0); disable_irq_nosync(host->irq); - queue_work(mmc_omap_wq, &host->cmd_abort_work); + queue_work(host->mmc_omap_wq, &host->cmd_abort_work); return IRQ_HANDLED; } @@ -1300,7 +1300,7 @@ static const struct mmc_host_ops mmc_omap_ops = { .set_ios = mmc_omap_set_ios, }; -static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id) +static int __devinit mmc_omap_new_slot(struct mmc_omap_host *host, int id) { struct mmc_omap_slot *slot = NULL; struct mmc_host *mmc; @@ -1389,13 +1389,13 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) tasklet_kill(&slot->cover_tasklet); del_timer_sync(&slot->cover_timer); - flush_workqueue(mmc_omap_wq); + flush_workqueue(slot->host->mmc_omap_wq); mmc_remove_host(mmc); mmc_free_host(mmc); } -static int __init mmc_omap_probe(struct platform_device *pdev) +static int __devinit mmc_omap_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_omap_host *host = NULL; @@ -1485,20 +1485,26 @@ static int __init mmc_omap_probe(struct platform_device *pdev) } host->nr_slots = pdata->nr_slots; + host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); + + host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); + if (!host->mmc_omap_wq) + goto err_plat_cleanup; + for (i = 0; i < pdata->nr_slots; i++) { ret = mmc_omap_new_slot(host, i); if (ret < 0) { while (--i >= 0) mmc_omap_remove_slot(host->slots[i]); - goto err_plat_cleanup; + goto err_destroy_wq; } } - host->reg_shift = (cpu_is_omap7xx() ? 1 : 2); - return 0; +err_destroy_wq: + destroy_workqueue(host->mmc_omap_wq); err_plat_cleanup: if (pdata->cleanup) pdata->cleanup(&pdev->dev); @@ -1518,7 +1524,7 @@ err_free_mem_region: return ret; } -static int mmc_omap_remove(struct platform_device *pdev) +static int __devexit mmc_omap_remove(struct platform_device *pdev) { struct mmc_omap_host *host = platform_get_drvdata(pdev); int i; @@ -1542,6 +1548,7 @@ static int mmc_omap_remove(struct platform_device *pdev) iounmap(host->virt_base); release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); + destroy_workqueue(host->mmc_omap_wq); kfree(host); @@ -1599,7 +1606,8 @@ static int mmc_omap_resume(struct platform_device *pdev) #endif static struct platform_driver mmc_omap_driver = { - .remove = mmc_omap_remove, + .probe = mmc_omap_probe, + .remove = __devexit_p(mmc_omap_remove), .suspend = mmc_omap_suspend, .resume = mmc_omap_resume, .driver = { @@ -1608,29 +1616,7 @@ static struct platform_driver mmc_omap_driver = { }, }; -static int __init mmc_omap_init(void) -{ - int ret; - - mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); - if (!mmc_omap_wq) - return -ENOMEM; - - ret = platform_driver_probe(&mmc_omap_driver, mmc_omap_probe); - if (ret) - destroy_workqueue(mmc_omap_wq); - return ret; -} - -static void __exit mmc_omap_exit(void) -{ - platform_driver_unregister(&mmc_omap_driver); - destroy_workqueue(mmc_omap_wq); -} - -module_init(mmc_omap_init); -module_exit(mmc_omap_exit); - +module_platform_driver(mmc_omap_driver); MODULE_DESCRIPTION("OMAP Multimedia Card driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 56d4499d4388..bc28627af66b 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -91,6 +91,7 @@ #define MSBS (1 << 5) #define BCE (1 << 1) #define FOUR_BIT (1 << 1) +#define DDR (1 << 19) #define DW8 (1 << 5) #define CC 0x1 #define TC 0x02 @@ -167,7 +168,6 @@ struct omap_hsmmc_host { int use_dma, dma_ch; int dma_line_tx, dma_line_rx; int slot_id; - int got_dbclk; int response_busy; int context_loss; int vdd; @@ -520,6 +520,10 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host) u32 con; con = OMAP_HSMMC_READ(host->base, CON); + if (ios->timing == MMC_TIMING_UHS_DDR50) + con |= DDR; /* configure in DDR mode */ + else + con &= ~DDR; switch (ios->bus_width) { case MMC_BUS_WIDTH_8: OMAP_HSMMC_WRITE(host->base, CON, con | DW8); @@ -796,11 +800,12 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) { int dma_ch; + unsigned long flags; - spin_lock(&host->irq_lock); + spin_lock_irqsave(&host->irq_lock, flags); host->req_in_progress = 0; dma_ch = host->dma_ch; - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ @@ -874,13 +879,14 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) { int dma_ch; + unsigned long flags; host->data->error = errno; - spin_lock(&host->irq_lock); + spin_lock_irqsave(&host->irq_lock, flags); dma_ch = host->dma_ch; host->dma_ch = -1; - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); if (host->use_dma && dma_ch != -1) { dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, @@ -1082,8 +1088,8 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) /* Disable the clocks */ pm_runtime_put_sync(host->dev); - if (host->got_dbclk) - clk_disable(host->dbclk); + if (host->dbclk) + clk_disable_unprepare(host->dbclk); /* Turn the power off */ ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); @@ -1093,8 +1099,8 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd); pm_runtime_get_sync(host->dev); - if (host->got_dbclk) - clk_enable(host->dbclk); + if (host->dbclk) + clk_prepare_enable(host->dbclk); if (ret != 0) goto err; @@ -1234,6 +1240,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) struct omap_hsmmc_host *host = cb_data; struct mmc_data *data; int dma_ch, req_in_progress; + unsigned long flags; if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n", @@ -1241,9 +1248,9 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) return; } - spin_lock(&host->irq_lock); + spin_lock_irqsave(&host->irq_lock, flags); if (host->dma_ch < 0) { - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); return; } @@ -1253,7 +1260,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) /* Fire up the next transfer. */ omap_hsmmc_config_dma_params(host, data, data->sg + host->dma_sg_idx); - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); return; } @@ -1264,7 +1271,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) req_in_progress = host->req_in_progress; dma_ch = host->dma_ch; host->dma_ch = -1; - spin_unlock(&host->irq_lock); + spin_unlock_irqrestore(&host->irq_lock, flags); omap_free_dma(dma_ch); @@ -1766,7 +1773,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) pdata->slots[0].nonremovable = true; pdata->slots[0].no_regulator_off_init = true; } - of_property_read_u32(np, "ti,bus-width", &bus_width); + of_property_read_u32(np, "bus-width", &bus_width); if (bus_width == 4) pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA; else if (bus_width == 8) @@ -1885,21 +1892,17 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_context_save(host); - if (cpu_is_omap2430()) { - host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); - /* - * MMC can still work without debounce clock. - */ - if (IS_ERR(host->dbclk)) - dev_warn(mmc_dev(host->mmc), - "Failed to get debounce clock\n"); - else - host->got_dbclk = 1; - - if (host->got_dbclk) - if (clk_enable(host->dbclk) != 0) - dev_dbg(mmc_dev(host->mmc), "Enabling debounce" - " clk failed\n"); + host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); + /* + * MMC can still work without debounce clock. + */ + if (IS_ERR(host->dbclk)) { + dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n"); + host->dbclk = NULL; + } else if (clk_prepare_enable(host->dbclk) != 0) { + dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n"); + clk_put(host->dbclk); + host->dbclk = NULL; } /* Since we do only SG emulation, we can have as many segs @@ -1928,6 +1931,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); if (!res) { dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); + ret = -ENXIO; goto err_irq; } host->dma_line_tx = res->start; @@ -1935,6 +1939,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); if (!res) { dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); + ret = -ENXIO; goto err_irq; } host->dma_line_rx = res->start; @@ -1969,7 +1974,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ret = request_threaded_irq(mmc_slot(host).card_detect_irq, NULL, omap_hsmmc_detect, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), @@ -2019,8 +2024,8 @@ err_irq: pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_put(host->fclk); - if (host->got_dbclk) { - clk_disable(host->dbclk); + if (host->dbclk) { + clk_disable_unprepare(host->dbclk); clk_put(host->dbclk); } err1: @@ -2030,7 +2035,9 @@ err1: err_alloc: omap_hsmmc_gpio_free(pdata); err: - release_mem_region(res->start, resource_size(res)); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); return ret; } @@ -2052,8 +2059,8 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_put(host->fclk); - if (host->got_dbclk) { - clk_disable(host->dbclk); + if (host->dbclk) { + clk_disable_unprepare(host->dbclk); clk_put(host->dbclk); } @@ -2110,8 +2117,8 @@ static int omap_hsmmc_suspend(struct device *dev) OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); } - if (host->got_dbclk) - clk_disable(host->dbclk); + if (host->dbclk) + clk_disable_unprepare(host->dbclk); err: pm_runtime_put_sync(host->dev); return ret; @@ -2131,8 +2138,8 @@ static int omap_hsmmc_resume(struct device *dev) pm_runtime_get_sync(host->dev); - if (host->got_dbclk) - clk_enable(host->dbclk); + if (host->dbclk) + clk_prepare_enable(host->dbclk); if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) omap_hsmmc_conf_bus_power(host); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index c3622a69f432..bd5a5cce122c 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -26,7 +26,6 @@ #include <mach/dma.h> #include <mach/regs-sdi.h> -#include <mach/regs-gpio.h> #include <plat/mci.h> @@ -1237,12 +1236,9 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: - s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); - s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); - s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); - s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2); - s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); + /* Configure GPE5...GPE10 pins in SD mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); if (host->pdata->set_power) host->pdata->set_power(ios->power_mode, ios->vdd); diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 177f697b5835..a6e53a1ebb08 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -20,11 +20,17 @@ */ #include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> #include <linux/module.h> #include <linux/mmc/host.h> #include "sdhci-pltfm.h" +struct sdhci_dove_priv { + struct clk *clk; +}; + static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) { u16 ret; @@ -66,16 +72,57 @@ static struct sdhci_pltfm_data sdhci_dove_pdata = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | - SDHCI_QUIRK_FORCE_DMA, + SDHCI_QUIRK_FORCE_DMA | + SDHCI_QUIRK_NO_HISPD_BIT, }; static int __devinit sdhci_dove_probe(struct platform_device *pdev) { - return sdhci_pltfm_register(pdev, &sdhci_dove_pdata); + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_dove_priv *priv; + int ret; + + ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata); + if (ret) + goto sdhci_dove_register_fail; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv), + GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to allocate private data"); + ret = -ENOMEM; + goto sdhci_dove_allocate_fail; + } + + host = platform_get_drvdata(pdev); + pltfm_host = sdhci_priv(host); + pltfm_host->priv = priv; + + priv->clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(priv->clk)) + clk_prepare_enable(priv->clk); + return 0; + +sdhci_dove_allocate_fail: + sdhci_pltfm_unregister(pdev); +sdhci_dove_register_fail: + return ret; } static int __devexit sdhci_dove_remove(struct platform_device *pdev) { + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_dove_priv *priv = pltfm_host->priv; + + if (priv->clk) { + if (!IS_ERR(priv->clk)) { + clk_disable_unprepare(priv->clk); + clk_put(priv->clk); + } + devm_kfree(&pdev->dev, priv->clk); + } return sdhci_pltfm_unregister(pdev); } diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 8abdaf6697a8..e23f8134591c 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -24,6 +24,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> #include <mach/esdhc.h> #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -68,7 +69,11 @@ struct pltfm_imx_data { int flags; u32 scratchpad; enum imx_esdhc_type devtype; + struct pinctrl *pinctrl; struct esdhc_platform_data boarddata; + struct clk *clk_ipg; + struct clk *clk_ahb; + struct clk *clk_per; }; static struct platform_device_id imx_esdhc_devtype[] = { @@ -294,6 +299,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; u32 new_val; switch (reg) { @@ -310,8 +317,11 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) SDHCI_CTRL_D3CD); /* ensure the endianess */ new_val |= ESDHC_HOST_CONTROL_LE; - /* DMA mode bits are shifted */ - new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; + /* bits 8&9 are reserved on mx25 */ + if (!is_imx25_esdhc(imx_data)) { + /* DMA mode bits are shifted */ + new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; + } esdhc_clrset_le(host, 0xffff, new_val, reg); return; @@ -402,7 +412,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (!np) return -ENODEV; - if (of_get_property(np, "fsl,card-wired", NULL)) + if (of_get_property(np, "non-removable", NULL)) boarddata->cd_type = ESDHC_CD_PERMANENT; if (of_get_property(np, "fsl,cd-controller", NULL)) @@ -437,7 +447,6 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host; struct sdhci_host *host; struct esdhc_platform_data *boarddata; - struct clk *clk; int err; struct pltfm_imx_data *imx_data; @@ -458,14 +467,35 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->devtype = pdev->id_entry->driver_data; pltfm_host->priv = imx_data; - clk = clk_get(mmc_dev(host->mmc), NULL); - if (IS_ERR(clk)) { - dev_err(mmc_dev(host->mmc), "clk err\n"); - err = PTR_ERR(clk); + imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(imx_data->clk_ipg)) { + err = PTR_ERR(imx_data->clk_ipg); + goto err_clk_get; + } + + imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(imx_data->clk_ahb)) { + err = PTR_ERR(imx_data->clk_ahb); + goto err_clk_get; + } + + imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(imx_data->clk_per)) { + err = PTR_ERR(imx_data->clk_per); goto err_clk_get; } - clk_prepare_enable(clk); - pltfm_host->clk = clk; + + pltfm_host->clk = imx_data->clk_per; + + clk_prepare_enable(imx_data->clk_per); + clk_prepare_enable(imx_data->clk_ipg); + clk_prepare_enable(imx_data->clk_ahb); + + imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(imx_data->pinctrl)) { + err = PTR_ERR(imx_data->pinctrl); + goto pin_err; + } host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; @@ -558,8 +588,10 @@ no_card_detect_irq: gpio_free(boarddata->wp_gpio); no_card_detect_pin: no_board_data: - clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); +pin_err: + clk_disable_unprepare(imx_data->clk_per); + clk_disable_unprepare(imx_data->clk_ipg); + clk_disable_unprepare(imx_data->clk_ahb); err_clk_get: kfree(imx_data); err_imx_data: @@ -585,8 +617,10 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) gpio_free(boarddata->cd_gpio); } - clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); + clk_disable_unprepare(imx_data->clk_per); + clk_disable_unprepare(imx_data->clk_ipg); + clk_disable_unprepare(imx_data->clk_ahb); + kfree(imx_data); sdhci_pltfm_free(pdev); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 69ef0beae104..504da715a41a 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -157,6 +157,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = { static const struct sdhci_pci_fixes sdhci_cafe = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, }; diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index c5c2a48bdd94..d9a4ef4f1ed0 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -42,7 +42,8 @@ static struct sdhci_ops sdhci_pltfm_ops = { #ifdef CONFIG_OF static bool sdhci_of_wp_inverted(struct device_node *np) { - if (of_get_property(np, "sdhci,wp-inverted", NULL)) + if (of_get_property(np, "sdhci,wp-inverted", NULL) || + of_get_property(np, "wp-inverted", NULL)) return true; /* Old device trees don't have the wp-inverted property. */ @@ -59,13 +60,16 @@ void sdhci_get_of_property(struct platform_device *pdev) struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); const __be32 *clk; + u32 bus_width; int size; if (of_device_is_available(np)) { if (of_get_property(np, "sdhci,auto-cmd12", NULL)) host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; - if (of_get_property(np, "sdhci,1-bit-only", NULL)) + if (of_get_property(np, "sdhci,1-bit-only", NULL) || + (of_property_read_u32(np, "bus-width", &bus_width) == 0 && + bus_width == 1)) host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; if (sdhci_of_wp_inverted(np)) diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index dbb75bfbcffb..b6ee8857e226 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -28,6 +28,9 @@ #include <linux/mmc/host.h> #include <linux/platform_data/pxa_sdhci.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_device.h> + #include "sdhci.h" #include "sdhci-pltfm.h" @@ -121,6 +124,48 @@ static struct sdhci_ops pxav2_sdhci_ops = { .platform_8bit_width = pxav2_mmc_set_width, }; +#ifdef CONFIG_OF +static const struct of_device_id sdhci_pxav2_of_match[] = { + { + .compatible = "mrvl,pxav2-mmc", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, sdhci_pxav2_of_match); + +static struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev) +{ + struct sdhci_pxa_platdata *pdata; + struct device_node *np = dev->of_node; + u32 bus_width; + u32 clk_delay_cycles; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + if (of_find_property(np, "non-removable", NULL)) + pdata->flags |= PXA_FLAG_CARD_PERMANENT; + + of_property_read_u32(np, "bus-width", &bus_width); + if (bus_width == 8) + pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT; + + of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); + if (clk_delay_cycles > 0) { + pdata->clk_delay_sel = 1; + pdata->clk_delay_cycles = clk_delay_cycles; + } + + return pdata; +} +#else +static inline struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev) +{ + return NULL; +} +#endif + static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; @@ -128,6 +173,8 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; + const struct of_device_id *match; + int ret; struct clk *clk; @@ -156,6 +203,10 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; + match = of_match_device(of_match_ptr(sdhci_pxav2_of_match), &pdev->dev); + if (match) { + pdata = pxav2_get_mmc_pdata(dev); + } if (pdata) { if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { /* on-chip device */ @@ -218,6 +269,9 @@ static struct platform_driver sdhci_pxav2_driver = { .driver = { .name = "sdhci-pxav2", .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = sdhci_pxav2_of_match, +#endif .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav2_probe, diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index f29695683556..07fe3834fe0b 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -28,6 +28,9 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> + #include "sdhci.h" #include "sdhci-pltfm.h" @@ -164,6 +167,46 @@ static struct sdhci_ops pxav3_sdhci_ops = { .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, }; +#ifdef CONFIG_OF +static const struct of_device_id sdhci_pxav3_of_match[] = { + { + .compatible = "mrvl,pxav3-mmc", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match); + +static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) +{ + struct sdhci_pxa_platdata *pdata; + struct device_node *np = dev->of_node; + u32 bus_width; + u32 clk_delay_cycles; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + if (of_find_property(np, "non-removable", NULL)) + pdata->flags |= PXA_FLAG_CARD_PERMANENT; + + of_property_read_u32(np, "bus-width", &bus_width); + if (bus_width == 8) + pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT; + + of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); + if (clk_delay_cycles > 0) + pdata->clk_delay_cycles = clk_delay_cycles; + + return pdata; +} +#else +static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) +{ + return NULL; +} +#endif + static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; @@ -171,6 +214,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; + const struct of_device_id *match; + int ret; struct clk *clk; @@ -202,6 +247,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; + match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); + if (match) + pdata = pxav3_get_mmc_pdata(dev); + if (pdata) { if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { /* on-chip device */ @@ -263,6 +312,9 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev) static struct platform_driver sdhci_pxav3_driver = { .driver = { .name = "sdhci-pxav3", +#ifdef CONFIG_OF + .of_match_table = sdhci_pxav3_of_match, +#endif .owner = THIS_MODULE, .pm = SDHCI_PLTFM_PMOPS, }, diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 55a164fcaa15..a50c205ea208 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -404,7 +404,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) if (sc->ext_cd_irq && request_threaded_irq(sc->ext_cd_irq, NULL, sdhci_s3c_gpio_card_detect_thread, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), sc) == 0) { int status = gpio_get_value(sc->ext_cd_gpio); if (pdata->ext_cd_gpio_invert) diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 6dfa82e03c7e..423da8194cd8 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -4,7 +4,7 @@ * Support of SDHCI platform devices for spear soc family * * Copyright (C) 2010 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> + * Viresh Kumar <viresh.linux@gmail.com> * * Inspired by sdhci-pltfm.c * @@ -75,8 +75,6 @@ static int __devinit sdhci_probe(struct platform_device *pdev) struct spear_sdhci *sdhci; int ret; - BUG_ON(pdev == NULL); - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { ret = -ENOMEM; @@ -84,18 +82,18 @@ static int __devinit sdhci_probe(struct platform_device *pdev) goto err; } - if (!request_mem_region(iomem->start, resource_size(iomem), - "spear-sdhci")) { + if (!devm_request_mem_region(&pdev->dev, iomem->start, + resource_size(iomem), "spear-sdhci")) { ret = -EBUSY; dev_dbg(&pdev->dev, "cannot request region\n"); goto err; } - sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL); + sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL); if (!sdhci) { ret = -ENOMEM; dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); - goto err_kzalloc; + goto err; } /* clk enable */ @@ -103,13 +101,13 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (IS_ERR(sdhci->clk)) { ret = PTR_ERR(sdhci->clk); dev_dbg(&pdev->dev, "Error getting clock\n"); - goto err_clk_get; + goto err; } ret = clk_enable(sdhci->clk); if (ret) { dev_dbg(&pdev->dev, "Error enabling clock\n"); - goto err_clk_enb; + goto put_clk; } /* overwrite platform_data */ @@ -124,7 +122,7 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (IS_ERR(host)) { ret = PTR_ERR(host); dev_dbg(&pdev->dev, "error allocating host\n"); - goto err_alloc_host; + goto disable_clk; } host->hw_name = "sdhci"; @@ -132,17 +130,18 @@ static int __devinit sdhci_probe(struct platform_device *pdev) host->irq = platform_get_irq(pdev, 0); host->quirks = SDHCI_QUIRK_BROKEN_ADMA; - host->ioaddr = ioremap(iomem->start, resource_size(iomem)); + host->ioaddr = devm_ioremap(&pdev->dev, iomem->start, + resource_size(iomem)); if (!host->ioaddr) { ret = -ENOMEM; dev_dbg(&pdev->dev, "failed to remap registers\n"); - goto err_ioremap; + goto free_host; } ret = sdhci_add_host(host); if (ret) { dev_dbg(&pdev->dev, "error adding host\n"); - goto err_add_host; + goto free_host; } platform_set_drvdata(pdev, host); @@ -161,11 +160,12 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (sdhci->data->card_power_gpio >= 0) { int val = 0; - ret = gpio_request(sdhci->data->card_power_gpio, "sdhci"); + ret = devm_gpio_request(&pdev->dev, + sdhci->data->card_power_gpio, "sdhci"); if (ret < 0) { dev_dbg(&pdev->dev, "gpio request fail: %d\n", sdhci->data->card_power_gpio); - goto err_pgpio_request; + goto set_drvdata; } if (sdhci->data->power_always_enb) @@ -177,60 +177,48 @@ static int __devinit sdhci_probe(struct platform_device *pdev) if (ret) { dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", sdhci->data->card_power_gpio); - goto err_pgpio_direction; + goto set_drvdata; } } if (sdhci->data->card_int_gpio >= 0) { - ret = gpio_request(sdhci->data->card_int_gpio, "sdhci"); + ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio, + "sdhci"); if (ret < 0) { dev_dbg(&pdev->dev, "gpio request fail: %d\n", sdhci->data->card_int_gpio); - goto err_igpio_request; + goto set_drvdata; } ret = gpio_direction_input(sdhci->data->card_int_gpio); if (ret) { dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", sdhci->data->card_int_gpio); - goto err_igpio_direction; + goto set_drvdata; } - ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio), + ret = devm_request_irq(&pdev->dev, + gpio_to_irq(sdhci->data->card_int_gpio), sdhci_gpio_irq, IRQF_TRIGGER_LOW, mmc_hostname(host->mmc), pdev); if (ret) { dev_dbg(&pdev->dev, "gpio request irq fail: %d\n", sdhci->data->card_int_gpio); - goto err_igpio_request_irq; + goto set_drvdata; } } return 0; -err_igpio_request_irq: -err_igpio_direction: - if (sdhci->data->card_int_gpio >= 0) - gpio_free(sdhci->data->card_int_gpio); -err_igpio_request: -err_pgpio_direction: - if (sdhci->data->card_power_gpio >= 0) - gpio_free(sdhci->data->card_power_gpio); -err_pgpio_request: +set_drvdata: platform_set_drvdata(pdev, NULL); sdhci_remove_host(host, 1); -err_add_host: - iounmap(host->ioaddr); -err_ioremap: +free_host: sdhci_free_host(host); -err_alloc_host: +disable_clk: clk_disable(sdhci->clk); -err_clk_enb: +put_clk: clk_put(sdhci->clk); -err_clk_get: - kfree(sdhci); -err_kzalloc: - release_mem_region(iomem->start, resource_size(iomem)); err: dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); return ret; @@ -239,35 +227,19 @@ err: static int __devexit sdhci_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); - int dead; + int dead = 0; u32 scratch; - if (sdhci->data) { - if (sdhci->data->card_int_gpio >= 0) { - free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev); - gpio_free(sdhci->data->card_int_gpio); - } - - if (sdhci->data->card_power_gpio >= 0) - gpio_free(sdhci->data->card_power_gpio); - } - platform_set_drvdata(pdev, NULL); - dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) dead = 1; sdhci_remove_host(host, dead); - iounmap(host->ioaddr); sdhci_free_host(host); clk_disable(sdhci->clk); clk_put(sdhci->clk); - kfree(sdhci); - if (iomem) - release_mem_region(iomem->start, resource_size(iomem)); return 0; } @@ -317,5 +289,5 @@ static struct platform_driver sdhci_driver = { module_platform_driver(sdhci_driver); MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); -MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); +MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 53b26502f6e2..0810ccc23d7e 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -32,8 +32,13 @@ #include "sdhci-pltfm.h" +/* Tegra SDHOST controller vendor register definitions */ +#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 +#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 + #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) +#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) struct sdhci_tegra_soc_data { struct sdhci_pltfm_data *pdata; @@ -120,6 +125,25 @@ static irqreturn_t carddetect_irq(int irq, void *data) return IRQ_HANDLED; }; +static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + + if (!(mask & SDHCI_RESET_ALL)) + return; + + /* Erratum: Enable SDHCI spec v3.00 support */ + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) { + u32 misc_ctrl; + + misc_ctrl = sdhci_readb(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); + misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; + sdhci_writeb(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); + } +} + static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -148,6 +172,7 @@ static struct sdhci_ops tegra_sdhci_ops = { .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .platform_8bit_width = tegra_sdhci_8bit, + .platform_reset_exit = tegra_sdhci_reset_exit, }; #ifdef CONFIG_ARCH_TEGRA_2x_SOC @@ -178,6 +203,7 @@ static struct sdhci_pltfm_data sdhci_tegra30_pdata = { static struct sdhci_tegra_soc_data soc_data_tegra30 = { .pdata = &sdhci_tegra30_pdata, + .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, }; #endif @@ -197,6 +223,7 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( { struct tegra_sdhci_platform_data *plat; struct device_node *np = pdev->dev.of_node; + u32 bus_width; if (!np) return NULL; @@ -210,7 +237,9 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0); - if (of_find_property(np, "support-8bit", NULL)) + + if (of_property_read_u32(np, "bus-width", &bus_width) == 0 && + bus_width == 8) plat->is_8bit = 1; return plat; @@ -269,7 +298,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate power gpio\n"); goto err_power_req; } - tegra_gpio_enable(plat->power_gpio); gpio_direction_output(plat->power_gpio, 1); } @@ -280,7 +308,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate cd gpio\n"); goto err_cd_req; } - tegra_gpio_enable(plat->cd_gpio); gpio_direction_input(plat->cd_gpio); rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, @@ -301,7 +328,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate wp gpio\n"); goto err_wp_req; } - tegra_gpio_enable(plat->wp_gpio); gpio_direction_input(plat->wp_gpio); } @@ -311,7 +337,7 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) rc = PTR_ERR(clk); goto err_clk_get; } - clk_enable(clk); + clk_prepare_enable(clk); pltfm_host->clk = clk; host->mmc->pm_caps = plat->pm_flags; @@ -326,26 +352,20 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) return 0; err_add_host: - clk_disable(pltfm_host->clk); + clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); err_clk_get: - if (gpio_is_valid(plat->wp_gpio)) { - tegra_gpio_disable(plat->wp_gpio); + if (gpio_is_valid(plat->wp_gpio)) gpio_free(plat->wp_gpio); - } err_wp_req: if (gpio_is_valid(plat->cd_gpio)) free_irq(gpio_to_irq(plat->cd_gpio), host); err_cd_irq_req: - if (gpio_is_valid(plat->cd_gpio)) { - tegra_gpio_disable(plat->cd_gpio); + if (gpio_is_valid(plat->cd_gpio)) gpio_free(plat->cd_gpio); - } err_cd_req: - if (gpio_is_valid(plat->power_gpio)) { - tegra_gpio_disable(plat->power_gpio); + if (gpio_is_valid(plat->power_gpio)) gpio_free(plat->power_gpio); - } err_power_req: err_no_plat: sdhci_pltfm_free(pdev); @@ -362,23 +382,18 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); - if (gpio_is_valid(plat->wp_gpio)) { - tegra_gpio_disable(plat->wp_gpio); + if (gpio_is_valid(plat->wp_gpio)) gpio_free(plat->wp_gpio); - } if (gpio_is_valid(plat->cd_gpio)) { free_irq(gpio_to_irq(plat->cd_gpio), host); - tegra_gpio_disable(plat->cd_gpio); gpio_free(plat->cd_gpio); } - if (gpio_is_valid(plat->power_gpio)) { - tegra_gpio_disable(plat->power_gpio); + if (gpio_is_valid(plat->power_gpio)) gpio_free(plat->power_gpio); - } - clk_disable(pltfm_host->clk); + clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); sdhci_pltfm_free(pdev); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ccefdebeff14..9a11dc39921c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -27,6 +27,7 @@ #include <linux/mmc/mmc.h> #include <linux/mmc/host.h> +#include <linux/mmc/card.h> #include "sdhci.h" @@ -244,6 +245,19 @@ static void sdhci_init(struct sdhci_host *host, int soft) static void sdhci_reinit(struct sdhci_host *host) { sdhci_init(host, 0); + /* + * Retuning stuffs are affected by different cards inserted and only + * applicable to UHS-I cards. So reset these fields to their initial + * value when card is removed. + */ + if (host->flags & SDHCI_USING_RETUNING_TIMER) { + host->flags &= ~SDHCI_USING_RETUNING_TIMER; + + del_timer_sync(&host->tuning_timer); + host->flags &= ~SDHCI_NEEDS_RETUNING; + host->mmc->max_blk_count = + (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; + } sdhci_enable_card_detection(host); } @@ -680,8 +694,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { - pr_warning("%s: Too large timeout requested for CMD%d!\n", - mmc_hostname(host->mmc), cmd->opcode); + DBG("%s: Too large timeout 0x%x requested for CMD%d!\n", + mmc_hostname(host->mmc), count, cmd->opcode); count = 0xE; } @@ -1245,6 +1259,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) struct sdhci_host *host; bool present; unsigned long flags; + u32 tuning_opcode; host = mmc_priv(mmc); @@ -1292,8 +1307,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) */ if ((host->flags & SDHCI_NEEDS_RETUNING) && !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { + /* eMMC uses cmd21 while sd and sdio use cmd19 */ + tuning_opcode = mmc->card->type == MMC_TYPE_MMC ? + MMC_SEND_TUNING_BLOCK_HS200 : + MMC_SEND_TUNING_BLOCK; spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc, mrq->cmd->opcode); + sdhci_execute_tuning(mmc, tuning_opcode); spin_lock_irqsave(&host->lock, flags); /* Restore original mmc_request structure */ @@ -1663,11 +1682,15 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, pwr = sdhci_readb(host, SDHCI_POWER_CONTROL); pwr &= ~SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + if (host->vmmc) + regulator_disable(host->vmmc); /* Wait for 1ms as per the spec */ usleep_range(1000, 1500); pwr |= SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + if (host->vmmc) + regulator_enable(host->vmmc); pr_info(DRIVER_NAME ": Switching to 1.8V signalling " "voltage failed, retrying with S18R set to 0\n"); @@ -1855,6 +1878,7 @@ out: */ if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count && (host->tuning_mode == SDHCI_TUNING_MODE_1)) { + host->flags |= SDHCI_USING_RETUNING_TIMER; mod_timer(&host->tuning_timer, jiffies + host->tuning_count * HZ); /* Tuning mode 1 limits the maximum data length to 4MB */ @@ -1872,10 +1896,10 @@ out: * try tuning again at a later time, when the re-tuning timer expires. * So for these controllers, we return 0. Since there might be other * controllers who do not have this capability, we return error for - * them. + * them. SDHCI_USING_RETUNING_TIMER means the host is currently using + * a retuning timer to do the retuning for the card. */ - if (err && host->tuning_count && - host->tuning_mode == SDHCI_TUNING_MODE_1) + if (err && (host->flags & SDHCI_USING_RETUNING_TIMER)) err = 0; sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); @@ -2382,7 +2406,6 @@ out: int sdhci_suspend_host(struct sdhci_host *host) { int ret; - bool has_tuning_timer; if (host->ops->platform_suspend) host->ops->platform_suspend(host); @@ -2390,16 +2413,14 @@ int sdhci_suspend_host(struct sdhci_host *host) sdhci_disable_card_detection(host); /* Disable tuning since we are suspending */ - has_tuning_timer = host->version >= SDHCI_SPEC_300 && - host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1; - if (has_tuning_timer) { + if (host->flags & SDHCI_USING_RETUNING_TIMER) { del_timer_sync(&host->tuning_timer); host->flags &= ~SDHCI_NEEDS_RETUNING; } ret = mmc_suspend_host(host->mmc); if (ret) { - if (has_tuning_timer) { + if (host->flags & SDHCI_USING_RETUNING_TIMER) { host->flags |= SDHCI_NEEDS_RETUNING; mod_timer(&host->tuning_timer, jiffies + host->tuning_count * HZ); @@ -2450,8 +2471,7 @@ int sdhci_resume_host(struct sdhci_host *host) host->ops->platform_resume(host); /* Set the re-tuning expiration flag */ - if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && - (host->tuning_mode == SDHCI_TUNING_MODE_1)) + if (host->flags & SDHCI_USING_RETUNING_TIMER) host->flags |= SDHCI_NEEDS_RETUNING; return ret; @@ -2490,8 +2510,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) int ret = 0; /* Disable tuning since we are suspending */ - if (host->version >= SDHCI_SPEC_300 && - host->tuning_mode == SDHCI_TUNING_MODE_1) { + if (host->flags & SDHCI_USING_RETUNING_TIMER) { del_timer_sync(&host->tuning_timer); host->flags &= ~SDHCI_NEEDS_RETUNING; } @@ -2532,8 +2551,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) sdhci_do_enable_preset_value(host, true); /* Set the re-tuning expiration flag */ - if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && - (host->tuning_mode == SDHCI_TUNING_MODE_1)) + if (host->flags & SDHCI_USING_RETUNING_TIMER) host->flags |= SDHCI_NEEDS_RETUNING; spin_lock_irqsave(&host->lock, flags); @@ -2584,7 +2602,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host); int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; - u32 caps[2]; + u32 caps[2] = {0, 0}; u32 max_current_caps; unsigned int ocr_avail; int ret; @@ -2614,8 +2632,10 @@ int sdhci_add_host(struct sdhci_host *host) caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : sdhci_readl(host, SDHCI_CAPABILITIES); - caps[1] = (host->version >= SDHCI_SPEC_300) ? - sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0; + if (host->version >= SDHCI_SPEC_300) + caps[1] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? + host->caps1 : + sdhci_readl(host, SDHCI_CAPABILITIES_1); if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_SDMA; @@ -2779,7 +2799,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && - mmc_card_is_removable(mmc)) + !(host->mmc->caps & MMC_CAP_NONREMOVABLE)) mmc->caps |= MMC_CAP_NEEDS_POLL; /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ @@ -2837,6 +2857,30 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_RETUNING_MODE_SHIFT; ocr_avail = 0; + + host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); + if (IS_ERR(host->vmmc)) { + pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); + host->vmmc = NULL; + } + +#ifdef CONFIG_REGULATOR + if (host->vmmc) { + ret = regulator_is_supported_voltage(host->vmmc, 3300000, + 3300000); + if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330))) + caps[0] &= ~SDHCI_CAN_VDD_330; + ret = regulator_is_supported_voltage(host->vmmc, 3000000, + 3000000); + if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300))) + caps[0] &= ~SDHCI_CAN_VDD_300; + ret = regulator_is_supported_voltage(host->vmmc, 1800000, + 1800000); + if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180))) + caps[0] &= ~SDHCI_CAN_VDD_180; + } +#endif /* CONFIG_REGULATOR */ + /* * According to SD Host Controller spec v3.00, if the Host System * can afford more than 150mA, Host Driver should set XPC to 1. Also @@ -2845,55 +2889,45 @@ int sdhci_add_host(struct sdhci_host *host) * value. */ max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); + if (!max_current_caps && host->vmmc) { + u32 curr = regulator_get_current_limit(host->vmmc); + if (curr > 0) { + + /* convert to SDHCI_MAX_CURRENT format */ + curr = curr/1000; /* convert to mA */ + curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER; + + curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT); + max_current_caps = + (curr << SDHCI_MAX_CURRENT_330_SHIFT) | + (curr << SDHCI_MAX_CURRENT_300_SHIFT) | + (curr << SDHCI_MAX_CURRENT_180_SHIFT); + } + } if (caps[0] & SDHCI_CAN_VDD_330) { - int max_current_330; - ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; - max_current_330 = ((max_current_caps & + mmc->max_current_330 = ((max_current_caps & SDHCI_MAX_CURRENT_330_MASK) >> SDHCI_MAX_CURRENT_330_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; - - if (max_current_330 > 150) - mmc->caps |= MMC_CAP_SET_XPC_330; } if (caps[0] & SDHCI_CAN_VDD_300) { - int max_current_300; - ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; - max_current_300 = ((max_current_caps & + mmc->max_current_300 = ((max_current_caps & SDHCI_MAX_CURRENT_300_MASK) >> SDHCI_MAX_CURRENT_300_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; - - if (max_current_300 > 150) - mmc->caps |= MMC_CAP_SET_XPC_300; } if (caps[0] & SDHCI_CAN_VDD_180) { - int max_current_180; - ocr_avail |= MMC_VDD_165_195; - max_current_180 = ((max_current_caps & + mmc->max_current_180 = ((max_current_caps & SDHCI_MAX_CURRENT_180_MASK) >> SDHCI_MAX_CURRENT_180_SHIFT) * SDHCI_MAX_CURRENT_MULTIPLIER; - - if (max_current_180 > 150) - mmc->caps |= MMC_CAP_SET_XPC_180; - - /* Maximum current capabilities of the host at 1.8V */ - if (max_current_180 >= 800) - mmc->caps |= MMC_CAP_MAX_CURRENT_800; - else if (max_current_180 >= 600) - mmc->caps |= MMC_CAP_MAX_CURRENT_600; - else if (max_current_180 >= 400) - mmc->caps |= MMC_CAP_MAX_CURRENT_400; - else - mmc->caps |= MMC_CAP_MAX_CURRENT_200; } mmc->ocr_avail = ocr_avail; @@ -2992,13 +3026,10 @@ int sdhci_add_host(struct sdhci_host *host) ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, mmc_hostname(mmc), host); - if (ret) + if (ret) { + pr_err("%s: Failed to request IRQ %d: %d\n", + mmc_hostname(mmc), host->irq, ret); goto untasklet; - - host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); - if (IS_ERR(host->vmmc)) { - pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); - host->vmmc = NULL; } sdhci_init(host, 0); @@ -3016,8 +3047,11 @@ int sdhci_add_host(struct sdhci_host *host) host->led.brightness_set = sdhci_led_control; ret = led_classdev_register(mmc_dev(mmc), &host->led); - if (ret) + if (ret) { + pr_err("%s: Failed to register LED device: %d\n", + mmc_hostname(mmc), ret); goto reset; + } #endif mmiowb(); @@ -3081,8 +3115,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) free_irq(host->irq, host); del_timer_sync(&host->timer); - if (host->version >= SDHCI_SPEC_300) - del_timer_sync(&host->tuning_timer); tasklet_kill(&host->card_tasklet); tasklet_kill(&host->finish_tasklet); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index f761f23d2a28..97653ea8942b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -205,6 +205,7 @@ #define SDHCI_CAPABILITIES_1 0x44 #define SDHCI_MAX_CURRENT 0x48 +#define SDHCI_MAX_CURRENT_LIMIT 0xFF #define SDHCI_MAX_CURRENT_330_MASK 0x0000FF #define SDHCI_MAX_CURRENT_330_SHIFT 0 #define SDHCI_MAX_CURRENT_300_MASK 0x00FF00 diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 724b35e85a26..5d8142773fac 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -54,6 +54,8 @@ #include <linux/mmc/mmc.h> #include <linux/mmc/sdio.h> #include <linux/mmc/sh_mmcif.h> +#include <linux/mmc/slot-gpio.h> +#include <linux/mod_devicetable.h> #include <linux/pagemap.h> #include <linux/platform_device.h> #include <linux/pm_qos.h> @@ -211,8 +213,6 @@ struct sh_mmcif_host { struct mmc_host *mmc; struct mmc_request *mrq; struct platform_device *pd; - struct sh_dmae_slave dma_slave_tx; - struct sh_dmae_slave dma_slave_rx; struct clk *hclk; unsigned int clk; int bus_width; @@ -371,56 +371,69 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) desc, cookie); } -static bool sh_mmcif_filter(struct dma_chan *chan, void *arg) -{ - dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); - chan->private = arg; - return true; -} - static void sh_mmcif_request_dma(struct sh_mmcif_host *host, struct sh_mmcif_plat_data *pdata) { - struct sh_dmae_slave *tx, *rx; + struct resource *res = platform_get_resource(host->pd, IORESOURCE_MEM, 0); + struct dma_slave_config cfg; + dma_cap_mask_t mask; + int ret; + host->dma_active = false; + if (!pdata) + return; + + if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0) + return; + /* We can only either use DMA for both Tx and Rx or not use it at all */ - if (pdata->dma) { - dev_warn(&host->pd->dev, - "Update your platform to use embedded DMA slave IDs\n"); - tx = &pdata->dma->chan_priv_tx; - rx = &pdata->dma->chan_priv_rx; - } else { - tx = &host->dma_slave_tx; - tx->slave_id = pdata->slave_id_tx; - rx = &host->dma_slave_rx; - rx->slave_id = pdata->slave_id_rx; - } - if (tx->slave_id > 0 && rx->slave_id > 0) { - dma_cap_mask_t mask; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + host->chan_tx = dma_request_channel(mask, shdma_chan_filter, + (void *)pdata->slave_id_tx); + dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, + host->chan_tx); - host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, tx); - dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, - host->chan_tx); + if (!host->chan_tx) + return; - if (!host->chan_tx) - return; + cfg.slave_id = pdata->slave_id_tx; + cfg.direction = DMA_MEM_TO_DEV; + cfg.dst_addr = res->start + MMCIF_CE_DATA; + cfg.src_addr = 0; + ret = dmaengine_slave_config(host->chan_tx, &cfg); + if (ret < 0) + goto ecfgtx; - host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, rx); - dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, - host->chan_rx); + host->chan_rx = dma_request_channel(mask, shdma_chan_filter, + (void *)pdata->slave_id_rx); + dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, + host->chan_rx); - if (!host->chan_rx) { - dma_release_channel(host->chan_tx); - host->chan_tx = NULL; - return; - } + if (!host->chan_rx) + goto erqrx; - init_completion(&host->dma_complete); - } + cfg.slave_id = pdata->slave_id_rx; + cfg.direction = DMA_DEV_TO_MEM; + cfg.dst_addr = 0; + cfg.src_addr = res->start + MMCIF_CE_DATA; + ret = dmaengine_slave_config(host->chan_rx, &cfg); + if (ret < 0) + goto ecfgrx; + + init_completion(&host->dma_complete); + + return; + +ecfgrx: + dma_release_channel(host->chan_rx); + host->chan_rx = NULL; +erqrx: +ecfgtx: + dma_release_channel(host->chan_tx); + host->chan_tx = NULL; } static void sh_mmcif_release_dma(struct sh_mmcif_host *host) @@ -444,13 +457,14 @@ static void sh_mmcif_release_dma(struct sh_mmcif_host *host) static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) { struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; + bool sup_pclk = p ? p->sup_pclk : false; sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR); if (!clk) return; - if (p->sup_pclk && clk == host->clk) + if (sup_pclk && clk == host->clk) sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); else sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & @@ -892,21 +906,15 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) switch (mrq->cmd->opcode) { /* MMCIF does not support SD/SDIO command */ - case SD_IO_SEND_OP_COND: + case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */ + case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ + if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR) + break; case MMC_APP_CMD: host->state = STATE_IDLE; mrq->cmd->error = -ETIMEDOUT; mmc_request_done(mmc, mrq); return; - case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ - if (!mrq->data) { - /* send_if_cond cmd (not support) */ - host->state = STATE_IDLE; - mrq->cmd->error = -ETIMEDOUT; - mmc_request_done(mmc, mrq); - return; - } - break; default: break; } @@ -916,10 +924,35 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) sh_mmcif_start_cmd(host, mrq); } +static int sh_mmcif_clk_update(struct sh_mmcif_host *host) +{ + int ret = clk_enable(host->hclk); + + if (!ret) { + host->clk = clk_get_rate(host->hclk); + host->mmc->f_max = host->clk / 2; + host->mmc->f_min = host->clk / 512; + } + + return ret; +} + +static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios) +{ + struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data; + struct mmc_host *mmc = host->mmc; + + if (pd && pd->set_pwr) + pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF); + if (!IS_ERR(mmc->supply.vmmc)) + /* Errors ignored... */ + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + ios->power_mode ? ios->vdd : 0); +} + static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sh_mmcif_host *host = mmc_priv(mmc); - struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; unsigned long flags; spin_lock_irqsave(&host->lock, flags); @@ -937,6 +970,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sh_mmcif_request_dma(host, host->pd->dev.platform_data); host->card_present = true; } + sh_mmcif_set_power(host, ios); } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { /* clock stop */ sh_mmcif_clock_control(host, 0); @@ -948,9 +982,10 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } if (host->power) { pm_runtime_put(&host->pd->dev); + clk_disable(host->hclk); host->power = false; - if (p->down_pwr && ios->power_mode == MMC_POWER_OFF) - p->down_pwr(host->pd); + if (ios->power_mode == MMC_POWER_OFF) + sh_mmcif_set_power(host, ios); } host->state = STATE_IDLE; return; @@ -958,8 +993,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->clock) { if (!host->power) { - if (p->set_pwr) - p->set_pwr(host->pd, ios->power_mode); + sh_mmcif_clk_update(host); pm_runtime_get_sync(&host->pd->dev); host->power = true; sh_mmcif_sync_reset(host); @@ -975,8 +1009,12 @@ static int sh_mmcif_get_cd(struct mmc_host *mmc) { struct sh_mmcif_host *host = mmc_priv(mmc); struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; + int ret = mmc_gpio_get_cd(mmc); + + if (ret >= 0) + return ret; - if (!p->get_cd) + if (!p || !p->get_cd) return -ENOSYS; else return p->get_cd(host->pd); @@ -1242,12 +1280,28 @@ static void mmcif_timeout_work(struct work_struct *work) mmc_request_done(host->mmc, mrq); } +static void sh_mmcif_init_ocr(struct sh_mmcif_host *host) +{ + struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data; + struct mmc_host *mmc = host->mmc; + + mmc_regulator_get_supply(mmc); + + if (!pd) + return; + + if (!mmc->ocr_avail) + mmc->ocr_avail = pd->ocr; + else if (pd->ocr) + dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); +} + static int __devinit sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; struct mmc_host *mmc; struct sh_mmcif_host *host; - struct sh_mmcif_plat_data *pd; + struct sh_mmcif_plat_data *pd = pdev->dev.platform_data; struct resource *res; void __iomem *reg; char clk_name[8]; @@ -1268,42 +1322,26 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) dev_err(&pdev->dev, "ioremap error.\n"); return -ENOMEM; } - pd = pdev->dev.platform_data; - if (!pd) { - dev_err(&pdev->dev, "sh_mmcif plat data error.\n"); - ret = -ENXIO; - goto clean_up; - } + mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; - goto clean_up; + goto ealloch; } host = mmc_priv(mmc); host->mmc = mmc; host->addr = reg; host->timeout = 1000; - snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); - host->hclk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(host->hclk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); - ret = PTR_ERR(host->hclk); - goto clean_up1; - } - clk_enable(host->hclk); - host->clk = clk_get_rate(host->hclk); host->pd = pdev; spin_lock_init(&host->lock); mmc->ops = &sh_mmcif_ops; - mmc->f_max = host->clk / 2; - mmc->f_min = host->clk / 512; - if (pd->ocr) - mmc->ocr_avail = pd->ocr; + sh_mmcif_init_ocr(host); + mmc->caps = MMC_CAP_MMC_HIGHSPEED; - if (pd->caps) + if (pd && pd->caps) mmc->caps |= pd->caps; mmc->max_segs = 32; mmc->max_blk_size = 512; @@ -1311,34 +1349,52 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size; mmc->max_seg_size = mmc->max_req_size; - sh_mmcif_sync_reset(host); platform_set_drvdata(pdev, host); pm_runtime_enable(&pdev->dev); host->power = false; + snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); + host->hclk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(host->hclk)) { + ret = PTR_ERR(host->hclk); + dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret); + goto eclkget; + } + ret = sh_mmcif_clk_update(host); + if (ret < 0) + goto eclkupdate; + ret = pm_runtime_resume(&pdev->dev); if (ret < 0) - goto clean_up2; + goto eresume; INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); + sh_mmcif_sync_reset(host); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host); if (ret) { dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n"); - goto clean_up3; + goto ereqirq0; } ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); if (ret) { dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); - goto clean_up4; + goto ereqirq1; + } + + if (pd && pd->use_cd_gpio) { + ret = mmc_gpio_request_cd(mmc, pd->cd_gpio); + if (ret < 0) + goto erqcd; } + clk_disable(host->hclk); ret = mmc_add_host(mmc); if (ret < 0) - goto clean_up5; + goto emmcaddh; dev_pm_qos_expose_latency_limit(&pdev->dev, 100); @@ -1347,33 +1403,42 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); return ret; -clean_up5: +emmcaddh: + if (pd && pd->use_cd_gpio) + mmc_gpio_free_cd(mmc); +erqcd: free_irq(irq[1], host); -clean_up4: +ereqirq1: free_irq(irq[0], host); -clean_up3: +ereqirq0: pm_runtime_suspend(&pdev->dev); -clean_up2: - pm_runtime_disable(&pdev->dev); +eresume: clk_disable(host->hclk); -clean_up1: +eclkupdate: + clk_put(host->hclk); +eclkget: + pm_runtime_disable(&pdev->dev); mmc_free_host(mmc); -clean_up: - if (reg) - iounmap(reg); +ealloch: + iounmap(reg); return ret; } static int __devexit sh_mmcif_remove(struct platform_device *pdev) { struct sh_mmcif_host *host = platform_get_drvdata(pdev); + struct sh_mmcif_plat_data *pd = pdev->dev.platform_data; int irq[2]; host->dying = true; + clk_enable(host->hclk); pm_runtime_get_sync(&pdev->dev); dev_pm_qos_hide_latency_limit(&pdev->dev); + if (pd && pd->use_cd_gpio) + mmc_gpio_free_cd(host->mmc); + mmc_remove_host(host->mmc); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); @@ -1395,9 +1460,9 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - clk_disable(host->hclk); mmc_free_host(host->mmc); pm_runtime_put_sync(&pdev->dev); + clk_disable(host->hclk); pm_runtime_disable(&pdev->dev); return 0; @@ -1406,24 +1471,18 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int sh_mmcif_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct sh_mmcif_host *host = platform_get_drvdata(pdev); + struct sh_mmcif_host *host = dev_get_drvdata(dev); int ret = mmc_suspend_host(host->mmc); - if (!ret) { + if (!ret) sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - clk_disable(host->hclk); - } return ret; } static int sh_mmcif_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct sh_mmcif_host *host = platform_get_drvdata(pdev); - - clk_enable(host->hclk); + struct sh_mmcif_host *host = dev_get_drvdata(dev); return mmc_resume_host(host->mmc); } @@ -1432,6 +1491,12 @@ static int sh_mmcif_resume(struct device *dev) #define sh_mmcif_resume NULL #endif /* CONFIG_PM */ +static const struct of_device_id mmcif_of_match[] = { + { .compatible = "renesas,sh-mmcif" }, + { } +}; +MODULE_DEVICE_TABLE(of, mmcif_of_match); + static const struct dev_pm_ops sh_mmcif_dev_pm_ops = { .suspend = sh_mmcif_suspend, .resume = sh_mmcif_resume, @@ -1443,6 +1508,8 @@ static struct platform_driver sh_mmcif_driver = { .driver = { .name = DRIVER_NAME, .pm = &sh_mmcif_dev_pm_ops, + .owner = THIS_MODULE, + .of_match_table = mmcif_of_match, }, }; diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 934b68e9efc3..0bdc146178db 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/mmc/host.h> @@ -39,22 +40,39 @@ struct sh_mobile_sdhi { struct tmio_mmc_dma dma_priv; }; +static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) +{ + struct mmc_host *mmc = dev_get_drvdata(&pdev->dev); + struct tmio_mmc_host *host = mmc_priv(mmc); + struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); + int ret = clk_enable(priv->clk); + if (ret < 0) + return ret; + + *f = clk_get_rate(priv->clk); + return 0; +} + +static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) +{ + struct mmc_host *mmc = dev_get_drvdata(&pdev->dev); + struct tmio_mmc_host *host = mmc_priv(mmc); + struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); + clk_disable(priv->clk); +} + static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state) { struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - if (p && p->set_pwr) - p->set_pwr(pdev, state); + p->set_pwr(pdev, state); } static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) { struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - if (p && p->get_cd) - return p->get_cd(pdev); - else - return -ENOSYS; + return p->get_cd(pdev); } static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) @@ -116,12 +134,14 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) } mmc_data = &priv->mmc_data; - p->pdata = mmc_data; - if (p->init) { - ret = p->init(pdev, &sdhi_ops); - if (ret) - goto einit; + if (p) { + p->pdata = mmc_data; + if (p->init) { + ret = p->init(pdev, &sdhi_ops); + if (ret) + goto einit; + } } snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); @@ -132,9 +152,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) goto eclkget; } - mmc_data->hclk = clk_get_rate(priv->clk); - mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; - mmc_data->get_cd = sh_mobile_sdhi_get_cd; + mmc_data->clk_enable = sh_mobile_sdhi_clk_enable; + mmc_data->clk_disable = sh_mobile_sdhi_clk_disable; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; if (p) { mmc_data->flags = p->tmio_flags; @@ -142,13 +161,18 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->capabilities |= p->tmio_caps; + mmc_data->capabilities2 |= p->tmio_caps2; mmc_data->cd_gpio = p->cd_gpio; + if (p->set_pwr) + mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; + if (p->get_cd) + mmc_data->get_cd = sh_mobile_sdhi_get_cd; if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) { - priv->param_tx.slave_id = p->dma_slave_tx; - priv->param_rx.slave_id = p->dma_slave_rx; - priv->dma_priv.chan_priv_tx = &priv->param_tx; - priv->dma_priv.chan_priv_rx = &priv->param_rx; + priv->param_tx.shdma_slave.slave_id = p->dma_slave_tx; + priv->param_rx.shdma_slave.slave_id = p->dma_slave_rx; + priv->dma_priv.chan_priv_tx = &priv->param_tx.shdma_slave; + priv->dma_priv.chan_priv_rx = &priv->param_rx.shdma_slave; priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ mmc_data->dma = &priv->dma_priv; } @@ -248,7 +272,7 @@ eirq_card_detect: eprobe: clk_put(priv->clk); eclkget: - if (p->cleanup) + if (p && p->cleanup) p->cleanup(pdev); einit: kfree(priv); @@ -263,7 +287,8 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; int i = 0, irq; - p->pdata = NULL; + if (p) + p->pdata = NULL; tmio_mmc_host_remove(host); @@ -276,7 +301,7 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) clk_put(priv->clk); - if (p->cleanup) + if (p && p->cleanup) p->cleanup(pdev); kfree(priv); @@ -291,11 +316,18 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { .runtime_resume = tmio_mmc_host_runtime_resume, }; +static const struct of_device_id sh_mobile_sdhi_of_match[] = { + { .compatible = "renesas,shmobile-sdhi" }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); + static struct platform_driver sh_mobile_sdhi_driver = { .driver = { .name = "sh_mobile_sdhi", .owner = THIS_MODULE, .pm = &tmio_mmc_dev_pm_ops, + .of_match_table = sh_mobile_sdhi_of_match, }, .probe = sh_mobile_sdhi_probe, .remove = __devexit_p(sh_mobile_sdhi_remove), diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 9a7996ade58e..0d8a9bbe30be 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -34,8 +34,9 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/mfd/tmio.h> -#include <linux/mmc/cd-gpio.h> #include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/slot-gpio.h> #include <linux/mmc/tmio.h> #include <linux/module.h> #include <linux/pagemap.h> @@ -305,8 +306,8 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command int c = cmd->opcode; u32 irq_mask = TMIO_MASK_CMD; - /* Command 12 is handled by hardware */ - if (cmd->opcode == 12 && !cmd->arg) { + /* CMD12 is handled by hardware */ + if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) { sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); return 0; } @@ -449,7 +450,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) } if (stop) { - if (stop->opcode == 12 && !stop->arg) + if (stop->opcode == MMC_STOP_TRANSMISSION && !stop->arg) sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); else BUG(); @@ -751,6 +752,34 @@ fail: mmc_request_done(mmc, mrq); } +static int tmio_mmc_clk_update(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct tmio_mmc_data *pdata = host->pdata; + int ret; + + if (!pdata->clk_enable) + return -ENOTSUPP; + + ret = pdata->clk_enable(host->pdev, &mmc->f_max); + if (!ret) + mmc->f_min = mmc->f_max / 512; + + return ret; +} + +static void tmio_mmc_set_power(struct tmio_mmc_host *host, struct mmc_ios *ios) +{ + struct mmc_host *mmc = host->mmc; + + if (host->set_pwr) + host->set_pwr(host->pdev, ios->power_mode != MMC_POWER_OFF); + if (!IS_ERR(mmc->supply.vmmc)) + /* Errors ignored... */ + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + ios->power_mode ? ios->vdd : 0); +} + /* Set MMC clock / power. * Note: This controller uses a simple divider scheme therefore it cannot * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as @@ -797,32 +826,37 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) */ if (ios->power_mode == MMC_POWER_ON && ios->clock) { if (!host->power) { + tmio_mmc_clk_update(mmc); pm_runtime_get_sync(dev); host->power = true; } tmio_mmc_set_clock(host, ios->clock); /* power up SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 1); + tmio_mmc_set_power(host, ios); /* start bus clock */ tmio_mmc_clk_start(host); } else if (ios->power_mode != MMC_POWER_UP) { - if (host->set_pwr && ios->power_mode == MMC_POWER_OFF) - host->set_pwr(host->pdev, 0); + if (ios->power_mode == MMC_POWER_OFF) + tmio_mmc_set_power(host, ios); if (host->power) { + struct tmio_mmc_data *pdata = host->pdata; + tmio_mmc_clk_stop(host); host->power = false; pm_runtime_put(dev); + if (pdata->clk_disable) + pdata->clk_disable(host->pdev); } - tmio_mmc_clk_stop(host); } - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); - break; - case MMC_BUS_WIDTH_4: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); - break; + if (host->power) { + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); + break; + case MMC_BUS_WIDTH_4: + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); + break; + } } /* Let things settle. delay taken from winCE driver */ @@ -841,6 +875,9 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_data *pdata = host->pdata; + int ret = mmc_gpio_get_ro(mmc); + if (ret >= 0) + return ret; return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); @@ -850,6 +887,9 @@ static int tmio_mmc_get_cd(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_data *pdata = host->pdata; + int ret = mmc_gpio_get_cd(mmc); + if (ret >= 0) + return ret; if (!pdata->get_cd) return -ENOSYS; @@ -865,6 +905,19 @@ static const struct mmc_host_ops tmio_mmc_ops = { .enable_sdio_irq = tmio_mmc_enable_sdio_irq, }; +static void tmio_mmc_init_ocr(struct tmio_mmc_host *host) +{ + struct tmio_mmc_data *pdata = host->pdata; + struct mmc_host *mmc = host->mmc; + + mmc_regulator_get_supply(mmc); + + if (!mmc->ocr_avail) + mmc->ocr_avail = pdata->ocr_mask ? : MMC_VDD_32_33 | MMC_VDD_33_34; + else if (pdata->ocr_mask) + dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); +} + int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, struct platform_device *pdev, struct tmio_mmc_data *pdata) @@ -904,18 +957,14 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc->ops = &tmio_mmc_ops; mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; - mmc->f_max = pdata->hclk; - mmc->f_min = mmc->f_max / 512; + mmc->caps2 = pdata->capabilities2; mmc->max_segs = 32; mmc->max_blk_size = 512; mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * mmc->max_segs; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; - if (pdata->ocr_mask) - mmc->ocr_avail = pdata->ocr_mask; - else - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + tmio_mmc_init_ocr(_host); _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || mmc->caps & MMC_CAP_NEEDS_POLL || @@ -927,6 +976,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, if (ret < 0) goto pm_disable; + if (tmio_mmc_clk_update(mmc) < 0) { + mmc->f_max = pdata->hclk; + mmc->f_min = mmc->f_max / 512; + } + /* * There are 4 different scenarios for the card detection: * 1) an external gpio irq handles the cd (best for power savings) @@ -937,7 +991,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, * While we increment the runtime PM counter for all scenarios when * the mmc core activates us by calling an appropriate set_ios(), we * must additionally ensure that in case 2) the tmio mmc hardware stays - * additionally ensure that in case 2) the tmio mmc hardware stays * powered on during runtime for the card detection to work. */ if (_host->native_hotplug) @@ -948,6 +1001,17 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); + + /* Unmask the IRQs we want to know about */ + if (!_host->chan_rx) + irq_mask |= TMIO_MASK_READOP; + if (!_host->chan_tx) + irq_mask |= TMIO_MASK_WRITEOP; + if (!_host->native_hotplug) + irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); + + _host->sdcard_irq_mask &= ~irq_mask; + if (pdata->flags & TMIO_MMC_SDIO_IRQ) tmio_mmc_enable_sdio_irq(mmc, 0); @@ -961,22 +1025,18 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, /* See if we also get DMA */ tmio_mmc_request_dma(_host, pdata); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (pdata->clk_disable) + pdata->clk_disable(pdev); + if (ret < 0) { + tmio_mmc_host_remove(_host); + return ret; + } dev_pm_qos_expose_latency_limit(&pdev->dev, 100); - /* Unmask the IRQs we want to know about */ - if (!_host->chan_rx) - irq_mask |= TMIO_MASK_READOP; - if (!_host->chan_tx) - irq_mask |= TMIO_MASK_WRITEOP; - if (!_host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); - - tmio_mmc_enable_mmc_irqs(_host, irq_mask); - if (pdata->flags & TMIO_MMC_USE_GPIO_CD) { - ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio); + ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio); if (ret < 0) { tmio_mmc_host_remove(_host); return ret; @@ -1008,7 +1068,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) * This means we can miss a card-eject, but this is anyway * possible, because of delayed processing of hotplug events. */ - mmc_cd_gpio_free(mmc); + mmc_gpio_free_cd(mmc); if (!host->native_hotplug) pm_runtime_get_sync(&pdev->dev); |