diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 121 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc.h | 2 |
2 files changed, 20 insertions, 103 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 545f62191afd..bb46b1b8d16b 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/mmc/dw_mmc.h> | 34 | #include <linux/mmc/dw_mmc.h> |
35 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
36 | #include <linux/regulator/consumer.h> | 36 | #include <linux/regulator/consumer.h> |
37 | #include <linux/workqueue.h> | ||
38 | #include <linux/of.h> | 37 | #include <linux/of.h> |
39 | #include <linux/of_gpio.h> | 38 | #include <linux/of_gpio.h> |
40 | #include <linux/mmc/slot-gpio.h> | 39 | #include <linux/mmc/slot-gpio.h> |
@@ -1959,6 +1958,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) | |||
1959 | tasklet_schedule(&host->tasklet); | 1958 | tasklet_schedule(&host->tasklet); |
1960 | } | 1959 | } |
1961 | 1960 | ||
1961 | static void dw_mci_handle_cd(struct dw_mci *host) | ||
1962 | { | ||
1963 | int i; | ||
1964 | |||
1965 | for (i = 0; i < host->num_slots; i++) { | ||
1966 | struct dw_mci_slot *slot = host->slot[i]; | ||
1967 | |||
1968 | if (!slot) | ||
1969 | continue; | ||
1970 | |||
1971 | if (slot->mmc->ops->card_event) | ||
1972 | slot->mmc->ops->card_event(slot->mmc); | ||
1973 | mmc_detect_change(slot->mmc, | ||
1974 | msecs_to_jiffies(host->pdata->detect_delay_ms)); | ||
1975 | } | ||
1976 | } | ||
1977 | |||
1962 | static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) | 1978 | static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) |
1963 | { | 1979 | { |
1964 | struct dw_mci *host = dev_id; | 1980 | struct dw_mci *host = dev_id; |
@@ -2034,7 +2050,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) | |||
2034 | 2050 | ||
2035 | if (pending & SDMMC_INT_CD) { | 2051 | if (pending & SDMMC_INT_CD) { |
2036 | mci_writel(host, RINTSTS, SDMMC_INT_CD); | 2052 | mci_writel(host, RINTSTS, SDMMC_INT_CD); |
2037 | queue_work(host->card_workqueue, &host->card_work); | 2053 | dw_mci_handle_cd(host); |
2038 | } | 2054 | } |
2039 | 2055 | ||
2040 | /* Handle SDIO Interrupts */ | 2056 | /* Handle SDIO Interrupts */ |
@@ -2061,88 +2077,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) | |||
2061 | return IRQ_HANDLED; | 2077 | return IRQ_HANDLED; |
2062 | } | 2078 | } |
2063 | 2079 | ||
2064 | static void dw_mci_work_routine_card(struct work_struct *work) | ||
2065 | { | ||
2066 | struct dw_mci *host = container_of(work, struct dw_mci, card_work); | ||
2067 | int i; | ||
2068 | |||
2069 | for (i = 0; i < host->num_slots; i++) { | ||
2070 | struct dw_mci_slot *slot = host->slot[i]; | ||
2071 | struct mmc_host *mmc = slot->mmc; | ||
2072 | struct mmc_request *mrq; | ||
2073 | int present; | ||
2074 | |||
2075 | present = dw_mci_get_cd(mmc); | ||
2076 | while (present != slot->last_detect_state) { | ||
2077 | dev_dbg(&slot->mmc->class_dev, "card %s\n", | ||
2078 | present ? "inserted" : "removed"); | ||
2079 | |||
2080 | spin_lock_bh(&host->lock); | ||
2081 | |||
2082 | /* Card change detected */ | ||
2083 | slot->last_detect_state = present; | ||
2084 | |||
2085 | /* Clean up queue if present */ | ||
2086 | mrq = slot->mrq; | ||
2087 | if (mrq) { | ||
2088 | if (mrq == host->mrq) { | ||
2089 | host->data = NULL; | ||
2090 | host->cmd = NULL; | ||
2091 | |||
2092 | switch (host->state) { | ||
2093 | case STATE_IDLE: | ||
2094 | case STATE_WAITING_CMD11_DONE: | ||
2095 | break; | ||
2096 | case STATE_SENDING_CMD11: | ||
2097 | case STATE_SENDING_CMD: | ||
2098 | mrq->cmd->error = -ENOMEDIUM; | ||
2099 | if (!mrq->data) | ||
2100 | break; | ||
2101 | /* fall through */ | ||
2102 | case STATE_SENDING_DATA: | ||
2103 | mrq->data->error = -ENOMEDIUM; | ||
2104 | dw_mci_stop_dma(host); | ||
2105 | break; | ||
2106 | case STATE_DATA_BUSY: | ||
2107 | case STATE_DATA_ERROR: | ||
2108 | if (mrq->data->error == -EINPROGRESS) | ||
2109 | mrq->data->error = -ENOMEDIUM; | ||
2110 | /* fall through */ | ||
2111 | case STATE_SENDING_STOP: | ||
2112 | if (mrq->stop) | ||
2113 | mrq->stop->error = -ENOMEDIUM; | ||
2114 | break; | ||
2115 | } | ||
2116 | |||
2117 | dw_mci_request_end(host, mrq); | ||
2118 | } else { | ||
2119 | list_del(&slot->queue_node); | ||
2120 | mrq->cmd->error = -ENOMEDIUM; | ||
2121 | if (mrq->data) | ||
2122 | mrq->data->error = -ENOMEDIUM; | ||
2123 | if (mrq->stop) | ||
2124 | mrq->stop->error = -ENOMEDIUM; | ||
2125 | |||
2126 | spin_unlock(&host->lock); | ||
2127 | mmc_request_done(slot->mmc, mrq); | ||
2128 | spin_lock(&host->lock); | ||
2129 | } | ||
2130 | } | ||
2131 | |||
2132 | /* Power down slot */ | ||
2133 | if (present == 0) | ||
2134 | dw_mci_reset(host); | ||
2135 | |||
2136 | spin_unlock_bh(&host->lock); | ||
2137 | |||
2138 | present = dw_mci_get_cd(mmc); | ||
2139 | } | ||
2140 | |||
2141 | mmc_detect_change(slot->mmc, | ||
2142 | msecs_to_jiffies(host->pdata->detect_delay_ms)); | ||
2143 | } | ||
2144 | } | ||
2145 | |||
2146 | #ifdef CONFIG_OF | 2080 | #ifdef CONFIG_OF |
2147 | /* given a slot id, find out the device node representing that slot */ | 2081 | /* given a slot id, find out the device node representing that slot */ |
2148 | static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) | 2082 | 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) | |||
2294 | dw_mci_init_debugfs(slot); | 2228 | dw_mci_init_debugfs(slot); |
2295 | #endif | 2229 | #endif |
2296 | 2230 | ||
2297 | /* Card initially undetected */ | ||
2298 | slot->last_detect_state = 0; | ||
2299 | |||
2300 | return 0; | 2231 | return 0; |
2301 | 2232 | ||
2302 | err_host_allocated: | 2233 | err_host_allocated: |
@@ -2677,17 +2608,10 @@ int dw_mci_probe(struct dw_mci *host) | |||
2677 | host->data_offset = DATA_240A_OFFSET; | 2608 | host->data_offset = DATA_240A_OFFSET; |
2678 | 2609 | ||
2679 | tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); | 2610 | tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); |
2680 | host->card_workqueue = alloc_workqueue("dw-mci-card", | ||
2681 | WQ_MEM_RECLAIM, 1); | ||
2682 | if (!host->card_workqueue) { | ||
2683 | ret = -ENOMEM; | ||
2684 | goto err_dmaunmap; | ||
2685 | } | ||
2686 | INIT_WORK(&host->card_work, dw_mci_work_routine_card); | ||
2687 | ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, | 2611 | ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, |
2688 | host->irq_flags, "dw-mci", host); | 2612 | host->irq_flags, "dw-mci", host); |
2689 | if (ret) | 2613 | if (ret) |
2690 | goto err_workqueue; | 2614 | goto err_dmaunmap; |
2691 | 2615 | ||
2692 | if (host->pdata->num_slots) | 2616 | if (host->pdata->num_slots) |
2693 | host->num_slots = host->pdata->num_slots; | 2617 | host->num_slots = host->pdata->num_slots; |
@@ -2723,7 +2647,7 @@ int dw_mci_probe(struct dw_mci *host) | |||
2723 | } else { | 2647 | } else { |
2724 | dev_dbg(host->dev, "attempted to initialize %d slots, " | 2648 | dev_dbg(host->dev, "attempted to initialize %d slots, " |
2725 | "but failed on all\n", host->num_slots); | 2649 | "but failed on all\n", host->num_slots); |
2726 | goto err_workqueue; | 2650 | goto err_dmaunmap; |
2727 | } | 2651 | } |
2728 | 2652 | ||
2729 | if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) | 2653 | if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) |
@@ -2731,9 +2655,6 @@ int dw_mci_probe(struct dw_mci *host) | |||
2731 | 2655 | ||
2732 | return 0; | 2656 | return 0; |
2733 | 2657 | ||
2734 | err_workqueue: | ||
2735 | destroy_workqueue(host->card_workqueue); | ||
2736 | |||
2737 | err_dmaunmap: | 2658 | err_dmaunmap: |
2738 | if (host->use_dma && host->dma_ops->exit) | 2659 | if (host->use_dma && host->dma_ops->exit) |
2739 | host->dma_ops->exit(host); | 2660 | host->dma_ops->exit(host); |
@@ -2767,8 +2688,6 @@ void dw_mci_remove(struct dw_mci *host) | |||
2767 | mci_writel(host, CLKENA, 0); | 2688 | mci_writel(host, CLKENA, 0); |
2768 | mci_writel(host, CLKSRC, 0); | 2689 | mci_writel(host, CLKSRC, 0); |
2769 | 2690 | ||
2770 | destroy_workqueue(host->card_workqueue); | ||
2771 | |||
2772 | if (host->use_dma && host->dma_ops->exit) | 2691 | if (host->use_dma && host->dma_ops->exit) |
2773 | host->dma_ops->exit(host); | 2692 | host->dma_ops->exit(host); |
2774 | 2693 | ||
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 01b99e8a9190..71d499557edc 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h | |||
@@ -214,7 +214,6 @@ extern int dw_mci_resume(struct dw_mci *host); | |||
214 | * with CONFIG_MMC_CLKGATE. | 214 | * with CONFIG_MMC_CLKGATE. |
215 | * @flags: Random state bits associated with the slot. | 215 | * @flags: Random state bits associated with the slot. |
216 | * @id: Number of this slot. | 216 | * @id: Number of this slot. |
217 | * @last_detect_state: Most recently observed card detect state. | ||
218 | */ | 217 | */ |
219 | struct dw_mci_slot { | 218 | struct dw_mci_slot { |
220 | struct mmc_host *mmc; | 219 | struct mmc_host *mmc; |
@@ -234,7 +233,6 @@ struct dw_mci_slot { | |||
234 | #define DW_MMC_CARD_PRESENT 0 | 233 | #define DW_MMC_CARD_PRESENT 0 |
235 | #define DW_MMC_CARD_NEED_INIT 1 | 234 | #define DW_MMC_CARD_NEED_INIT 1 |
236 | int id; | 235 | int id; |
237 | int last_detect_state; | ||
238 | }; | 236 | }; |
239 | 237 | ||
240 | struct dw_mci_tuning_data { | 238 | struct dw_mci_tuning_data { |