|
@@ -34,7 +34,6 @@
|
|
|
#include <linux/mmc/dw_mmc.h>
|
|
|
#include <linux/bitops.h>
|
|
|
#include <linux/regulator/consumer.h>
|
|
|
-#include <linux/workqueue.h>
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/of_gpio.h>
|
|
|
#include <linux/mmc/slot-gpio.h>
|
|
@@ -1959,6 +1958,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
|
|
|
tasklet_schedule(&host->tasklet);
|
|
|
}
|
|
|
|
|
|
+static void dw_mci_handle_cd(struct dw_mci *host)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < host->num_slots; i++) {
|
|
|
+ struct dw_mci_slot *slot = host->slot[i];
|
|
|
+
|
|
|
+ if (!slot)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (slot->mmc->ops->card_event)
|
|
|
+ slot->mmc->ops->card_event(slot->mmc);
|
|
|
+ mmc_detect_change(slot->mmc,
|
|
|
+ msecs_to_jiffies(host->pdata->detect_delay_ms));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|
|
{
|
|
|
struct dw_mci *host = dev_id;
|
|
@@ -2034,7 +2050,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(host->card_workqueue, &host->card_work);
|
|
|
+ dw_mci_handle_cd(host);
|
|
|
}
|
|
|
|
|
|
/* Handle SDIO Interrupts */
|
|
@@ -2061,88 +2077,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
-static void dw_mci_work_routine_card(struct work_struct *work)
|
|
|
-{
|
|
|
- struct dw_mci *host = container_of(work, struct dw_mci, card_work);
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < host->num_slots; i++) {
|
|
|
- struct dw_mci_slot *slot = host->slot[i];
|
|
|
- struct mmc_host *mmc = slot->mmc;
|
|
|
- struct mmc_request *mrq;
|
|
|
- int present;
|
|
|
-
|
|
|
- present = dw_mci_get_cd(mmc);
|
|
|
- while (present != slot->last_detect_state) {
|
|
|
- dev_dbg(&slot->mmc->class_dev, "card %s\n",
|
|
|
- present ? "inserted" : "removed");
|
|
|
-
|
|
|
- spin_lock_bh(&host->lock);
|
|
|
-
|
|
|
- /* Card change detected */
|
|
|
- slot->last_detect_state = present;
|
|
|
-
|
|
|
- /* Clean up queue if present */
|
|
|
- mrq = slot->mrq;
|
|
|
- if (mrq) {
|
|
|
- if (mrq == host->mrq) {
|
|
|
- host->data = NULL;
|
|
|
- host->cmd = NULL;
|
|
|
-
|
|
|
- switch (host->state) {
|
|
|
- case STATE_IDLE:
|
|
|
- case STATE_WAITING_CMD11_DONE:
|
|
|
- break;
|
|
|
- case STATE_SENDING_CMD11:
|
|
|
- case STATE_SENDING_CMD:
|
|
|
- mrq->cmd->error = -ENOMEDIUM;
|
|
|
- if (!mrq->data)
|
|
|
- break;
|
|
|
- /* fall through */
|
|
|
- case STATE_SENDING_DATA:
|
|
|
- mrq->data->error = -ENOMEDIUM;
|
|
|
- dw_mci_stop_dma(host);
|
|
|
- break;
|
|
|
- case STATE_DATA_BUSY:
|
|
|
- case STATE_DATA_ERROR:
|
|
|
- if (mrq->data->error == -EINPROGRESS)
|
|
|
- mrq->data->error = -ENOMEDIUM;
|
|
|
- /* fall through */
|
|
|
- case STATE_SENDING_STOP:
|
|
|
- if (mrq->stop)
|
|
|
- mrq->stop->error = -ENOMEDIUM;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- dw_mci_request_end(host, mrq);
|
|
|
- } else {
|
|
|
- list_del(&slot->queue_node);
|
|
|
- mrq->cmd->error = -ENOMEDIUM;
|
|
|
- if (mrq->data)
|
|
|
- mrq->data->error = -ENOMEDIUM;
|
|
|
- if (mrq->stop)
|
|
|
- mrq->stop->error = -ENOMEDIUM;
|
|
|
-
|
|
|
- spin_unlock(&host->lock);
|
|
|
- mmc_request_done(slot->mmc, mrq);
|
|
|
- spin_lock(&host->lock);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Power down slot */
|
|
|
- if (present == 0)
|
|
|
- dw_mci_reset(host);
|
|
|
-
|
|
|
- spin_unlock_bh(&host->lock);
|
|
|
-
|
|
|
- present = dw_mci_get_cd(mmc);
|
|
|
- }
|
|
|
-
|
|
|
- mmc_detect_change(slot->mmc,
|
|
|
- msecs_to_jiffies(host->pdata->detect_delay_ms));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
#ifdef CONFIG_OF
|
|
|
/* given a slot id, find out the device node representing that slot */
|
|
|
static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
|
|
@@ -2294,9 +2228,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
|
|
|
dw_mci_init_debugfs(slot);
|
|
|
#endif
|
|
|
|
|
|
- /* Card initially undetected */
|
|
|
- slot->last_detect_state = 0;
|
|
|
-
|
|
|
return 0;
|
|
|
|
|
|
err_host_allocated:
|
|
@@ -2677,17 +2608,10 @@ int dw_mci_probe(struct dw_mci *host)
|
|
|
host->data_offset = DATA_240A_OFFSET;
|
|
|
|
|
|
tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
|
|
|
- host->card_workqueue = alloc_workqueue("dw-mci-card",
|
|
|
- WQ_MEM_RECLAIM, 1);
|
|
|
- if (!host->card_workqueue) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err_dmaunmap;
|
|
|
- }
|
|
|
- INIT_WORK(&host->card_work, dw_mci_work_routine_card);
|
|
|
ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
|
|
|
host->irq_flags, "dw-mci", host);
|
|
|
if (ret)
|
|
|
- goto err_workqueue;
|
|
|
+ goto err_dmaunmap;
|
|
|
|
|
|
if (host->pdata->num_slots)
|
|
|
host->num_slots = host->pdata->num_slots;
|
|
@@ -2723,7 +2647,7 @@ int dw_mci_probe(struct dw_mci *host)
|
|
|
} else {
|
|
|
dev_dbg(host->dev, "attempted to initialize %d slots, "
|
|
|
"but failed on all\n", host->num_slots);
|
|
|
- goto err_workqueue;
|
|
|
+ goto err_dmaunmap;
|
|
|
}
|
|
|
|
|
|
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
|
|
@@ -2731,9 +2655,6 @@ int dw_mci_probe(struct dw_mci *host)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
-err_workqueue:
|
|
|
- destroy_workqueue(host->card_workqueue);
|
|
|
-
|
|
|
err_dmaunmap:
|
|
|
if (host->use_dma && host->dma_ops->exit)
|
|
|
host->dma_ops->exit(host);
|
|
@@ -2767,8 +2688,6 @@ void dw_mci_remove(struct dw_mci *host)
|
|
|
mci_writel(host, CLKENA, 0);
|
|
|
mci_writel(host, CLKSRC, 0);
|
|
|
|
|
|
- destroy_workqueue(host->card_workqueue);
|
|
|
-
|
|
|
if (host->use_dma && host->dma_ops->exit)
|
|
|
host->dma_ops->exit(host);
|
|
|
|