diff options
Diffstat (limited to 'drivers/mmc/host/dw_mmc.c')
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 225 |
1 files changed, 94 insertions, 131 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index e45129f48174..a9dfb26972f2 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -392,7 +392,7 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) cmdr = stop->opcode | SDMMC_CMD_STOP | SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; - if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags)) + if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags)) cmdr |= SDMMC_CMD_USE_HOLD_REG; return cmdr; @@ -480,7 +480,7 @@ static void dw_mci_dmac_complete_dma(void *arg) if ((host->use_dma == TRANS_MODE_EDMAC) && data && (data->flags & MMC_DATA_READ)) /* Invalidate cache after read */ - dma_sync_sg_for_cpu(mmc_dev(host->cur_slot->mmc), + dma_sync_sg_for_cpu(mmc_dev(host->slot->mmc), data->sg, data->sg_len, DMA_FROM_DEVICE); @@ -820,7 +820,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host, /* Flush cache before write */ if (host->data->flags & MMC_DATA_WRITE) - dma_sync_sg_for_device(mmc_dev(host->cur_slot->mmc), sgl, + dma_sync_sg_for_device(mmc_dev(host->slot->mmc), sgl, sg_elems, DMA_TO_DEVICE); dma_async_issue_pending(host->dms->ch); @@ -1282,7 +1282,6 @@ static void __dw_mci_start_request(struct dw_mci *host, mrq = slot->mrq; - host->cur_slot = slot; host->mrq = mrq; host->pending_events = 0; @@ -1621,16 +1620,10 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { - if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) { - pm_runtime_get_noresume(mmc->parent); - set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); - } + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); clk_en_a = clk_en_a_old & ~clken_low_pwr; } else { - if (test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) { - pm_runtime_put_noidle(mmc->parent); - clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); - } + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); clk_en_a = clk_en_a_old | clken_low_pwr; } @@ -1642,9 +1635,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) } } -static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) +static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb) { - struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; unsigned long irqflags; u32 int_mask; @@ -1662,6 +1654,27 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) spin_unlock_irqrestore(&host->irq_lock, irqflags); } +static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + + __dw_mci_enable_sdio_irq(slot, enb); + + /* Avoid runtime suspending the device when SDIO IRQ is enabled */ + if (enb) + pm_runtime_get_noresume(host->dev); + else + pm_runtime_put_noidle(host->dev); +} + +static void dw_mci_ack_sdio_irq(struct mmc_host *mmc) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + + __dw_mci_enable_sdio_irq(slot, 1); +} + static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct dw_mci_slot *slot = mmc_priv(mmc); @@ -1749,7 +1762,7 @@ static bool dw_mci_reset(struct dw_mci *host) ciu_out: /* After a CTRL reset we need to have CIU set clock registers */ - mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + mci_send_cmd(host->slot, SDMMC_CMD_UPD_CLK, 0); return ret; } @@ -1763,6 +1776,7 @@ static const struct mmc_host_ops dw_mci_ops = { .get_cd = dw_mci_get_cd, .hw_reset = dw_mci_hw_reset, .enable_sdio_irq = dw_mci_enable_sdio_irq, + .ack_sdio_irq = dw_mci_ack_sdio_irq, .execute_tuning = dw_mci_execute_tuning, .card_busy = dw_mci_card_busy, .start_signal_voltage_switch = dw_mci_switch_voltage, @@ -1775,11 +1789,11 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) __acquires(&host->lock) { struct dw_mci_slot *slot; - struct mmc_host *prev_mmc = host->cur_slot->mmc; + struct mmc_host *prev_mmc = host->slot->mmc; WARN_ON(host->cmd || host->data); - host->cur_slot->mrq = NULL; + host->slot->mrq = NULL; host->mrq = NULL; if (!list_empty(&host->queue)) { slot = list_entry(host->queue.next, @@ -1929,7 +1943,7 @@ static void dw_mci_tasklet_func(unsigned long priv) err = dw_mci_command_complete(host, cmd); if (cmd == mrq->sbc && !err) { prev_state = state = STATE_SENDING_CMD; - __dw_mci_start_request(host, host->cur_slot, + __dw_mci_start_request(host, host->slot, mrq->cmd); goto unlock; } @@ -2548,26 +2562,19 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) static void dw_mci_handle_cd(struct dw_mci *host) { - int i; + struct dw_mci_slot *slot = host->slot; - 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)); - } + 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; u32 pending; - int i; + struct dw_mci_slot *slot = host->slot; pending = mci_readl(host, MINTSTS); /* read-only mask reg */ @@ -2644,18 +2651,11 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) dw_mci_handle_cd(host); } - /* Handle SDIO Interrupts */ - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - - if (!slot) - continue; - - if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { - mci_writel(host, RINTSTS, - SDMMC_INT_SDIO(slot->sdio_id)); - mmc_signal_sdio_irq(slot->mmc); - } + if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { + mci_writel(host, RINTSTS, + SDMMC_INT_SDIO(slot->sdio_id)); + __dw_mci_enable_sdio_irq(slot, 0); + sdio_signal_irq(slot->mmc); } } @@ -2687,7 +2687,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) +static int dw_mci_init_slot(struct dw_mci *host) { struct mmc_host *mmc; struct dw_mci_slot *slot; @@ -2700,15 +2700,15 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) return -ENOMEM; slot = mmc_priv(mmc); - slot->id = id; - slot->sdio_id = host->sdio_id0 + id; + slot->id = 0; + slot->sdio_id = host->sdio_id0 + slot->id; slot->mmc = mmc; slot->host = host; - host->slot[id] = slot; + host->slot = slot; mmc->ops = &dw_mci_ops; - if (of_property_read_u32_array(host->dev->of_node, - "clock-freq-min-max", freq, 2)) { + if (device_property_read_u32_array(host->dev, "clock-freq-min-max", + freq, 2)) { mmc->f_min = DW_MCI_FREQ_MIN; mmc->f_max = DW_MCI_FREQ_MAX; } else { @@ -2755,6 +2755,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (ret) goto err_host_allocated; + /* Process SDIO IRQs through the sdio_irq_work. */ + if (mmc->caps & MMC_CAP_SDIO_IRQ) + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + /* Useful defaults if platform data is unset. */ if (host->use_dma == TRANS_MODE_IDMAC) { mmc->max_segs = host->ring_size; @@ -2796,11 +2800,11 @@ err_host_allocated: return ret; } -static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) +static void dw_mci_cleanup_slot(struct dw_mci_slot *slot) { /* Debugfs stuff is cleaned up by mmc core */ mmc_remove_host(slot->mmc); - slot->host->slot[id] = NULL; + slot->host->slot = NULL; mmc_free_host(slot->mmc); } @@ -2808,7 +2812,6 @@ static void dw_mci_init_dma(struct dw_mci *host) { int addr_config; struct device *dev = host->dev; - struct device_node *np = dev->of_node; /* * Check tansfer mode from HCON[17:16] @@ -2869,8 +2872,9 @@ static void dw_mci_init_dma(struct dw_mci *host) dev_info(host->dev, "Using internal DMA controller.\n"); } else { /* TRANS_MODE_EDMAC: check dma bindings again */ - if ((of_property_count_strings(np, "dma-names") < 0) || - (!of_find_property(np, "dmas", NULL))) { + if ((device_property_read_string_array(dev, "dma-names", + NULL, 0) < 0) || + !device_property_present(dev, "dmas")) { goto no_dma; } host->dma_ops = &dw_mci_edmac_ops; @@ -2937,7 +2941,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) { struct dw_mci_board *pdata; struct device *dev = host->dev; - struct device_node *np = dev->of_node; const struct dw_mci_drv_data *drv_data = host->drv_data; int ret; u32 clock_frequency; @@ -2954,20 +2957,22 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) } /* find out number of slots supported */ - of_property_read_u32(np, "num-slots", &pdata->num_slots); + if (device_property_read_u32(dev, "num-slots", &pdata->num_slots)) + dev_info(dev, "'num-slots' was deprecated.\n"); - if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) + if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth)) dev_info(dev, "fifo-depth property not found, using value of FIFOTH register as default\n"); - of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); + device_property_read_u32(dev, "card-detect-delay", + &pdata->detect_delay_ms); - of_property_read_u32(np, "data-addr", &host->data_addr_override); + device_property_read_u32(dev, "data-addr", &host->data_addr_override); - if (of_get_property(np, "fifo-watermark-aligned", NULL)) + if (device_property_present(dev, "fifo-watermark-aligned")) host->wm_aligned = true; - if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) + if (!device_property_read_u32(dev, "clock-frequency", &clock_frequency)) pdata->bus_hz = clock_frequency; if (drv_data && drv_data->parse_dt) { @@ -2990,29 +2995,21 @@ static void dw_mci_enable_cd(struct dw_mci *host) { unsigned long irqflags; u32 temp; - int i; - struct dw_mci_slot *slot; /* * No need for CD if all slots have a non-error GPIO * as well as broken card detection is found. */ - for (i = 0; i < host->num_slots; i++) { - slot = host->slot[i]; - if (slot->mmc->caps & MMC_CAP_NEEDS_POLL) - return; - - if (mmc_gpio_get_cd(slot->mmc) < 0) - break; - } - if (i == host->num_slots) + if (host->slot->mmc->caps & MMC_CAP_NEEDS_POLL) return; - spin_lock_irqsave(&host->irq_lock, irqflags); - temp = mci_readl(host, INTMASK); - temp |= SDMMC_INT_CD; - mci_writel(host, INTMASK, temp); - spin_unlock_irqrestore(&host->irq_lock, irqflags); + if (mmc_gpio_get_cd(host->slot->mmc) < 0) { + spin_lock_irqsave(&host->irq_lock, irqflags); + temp = mci_readl(host, INTMASK); + temp |= SDMMC_INT_CD; + mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->irq_lock, irqflags); + } } int dw_mci_probe(struct dw_mci *host) @@ -3020,7 +3017,6 @@ int dw_mci_probe(struct dw_mci *host) const struct dw_mci_drv_data *drv_data = host->drv_data; int width, i, ret = 0; u32 fifo_size; - int init_slots = 0; if (!host->pdata) { host->pdata = dw_mci_parse_dt(host); @@ -3183,19 +3179,6 @@ int dw_mci_probe(struct dw_mci *host) if (ret) goto err_dmaunmap; - if (host->pdata->num_slots) - host->num_slots = host->pdata->num_slots; - else - host->num_slots = 1; - - if (host->num_slots < 1 || - host->num_slots > SDMMC_GET_SLOT_NUM(mci_readl(host, HCON))) { - dev_err(host->dev, - "Platform data must supply correct num_slots.\n"); - ret = -ENODEV; - goto err_clk_ciu; - } - /* * Enable interrupts for command done, data over, data empty, * receive ready and error such as transmit, receive timeout, crc error @@ -3211,20 +3194,9 @@ int dw_mci_probe(struct dw_mci *host) host->irq, width, fifo_size); /* We need at least one slot to succeed */ - for (i = 0; i < host->num_slots; i++) { - ret = dw_mci_init_slot(host, i); - if (ret) - dev_dbg(host->dev, "slot %d init failed\n", i); - else - init_slots++; - } - - if (init_slots) { - dev_info(host->dev, "%d slots initialized\n", init_slots); - } else { - dev_dbg(host->dev, - "attempted to initialize %d slots, but failed on all\n", - host->num_slots); + ret = dw_mci_init_slot(host); + if (ret) { + dev_dbg(host->dev, "slot %d init failed\n", i); goto err_dmaunmap; } @@ -3252,13 +3224,9 @@ EXPORT_SYMBOL(dw_mci_probe); void dw_mci_remove(struct dw_mci *host) { - int i; - - for (i = 0; i < host->num_slots; i++) { - dev_dbg(host->dev, "remove slot %d\n", i); - if (host->slot[i]) - dw_mci_cleanup_slot(host->slot[i], i); - } + dev_dbg(host->dev, "remove slot\n"); + if (host->slot) + dw_mci_cleanup_slot(host->slot); mci_writel(host, RINTSTS, 0xFFFFFFFF); mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ @@ -3290,9 +3258,9 @@ int dw_mci_runtime_suspend(struct device *dev) clk_disable_unprepare(host->ciu_clk); - if (host->cur_slot && - (mmc_can_gpio_cd(host->cur_slot->mmc) || - !mmc_card_is_removable(host->cur_slot->mmc))) + if (host->slot && + (mmc_can_gpio_cd(host->slot->mmc) || + !mmc_card_is_removable(host->slot->mmc))) clk_disable_unprepare(host->biu_clk); return 0; @@ -3301,12 +3269,12 @@ EXPORT_SYMBOL(dw_mci_runtime_suspend); int dw_mci_runtime_resume(struct device *dev) { - int i, ret = 0; + int ret = 0; struct dw_mci *host = dev_get_drvdata(dev); - if (host->cur_slot && - (mmc_can_gpio_cd(host->cur_slot->mmc) || - !mmc_card_is_removable(host->cur_slot->mmc))) { + if (host->slot && + (mmc_can_gpio_cd(host->slot->mmc) || + !mmc_card_is_removable(host->slot->mmc))) { ret = clk_prepare_enable(host->biu_clk); if (ret) return ret; @@ -3341,17 +3309,12 @@ int dw_mci_runtime_resume(struct device *dev) DW_MCI_ERROR_FLAGS); mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - if (!slot) - continue; - if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) - dw_mci_set_ios(slot->mmc, &slot->mmc->ios); + if (host->slot->mmc->pm_flags & MMC_PM_KEEP_POWER) + dw_mci_set_ios(host->slot->mmc, &host->slot->mmc->ios); - /* Force setup bus to guarantee available clock output */ - dw_mci_setup_bus(slot, true); - } + /* Force setup bus to guarantee available clock output */ + dw_mci_setup_bus(host->slot, true); /* Now that slots are all setup, we can enable card detect */ dw_mci_enable_cd(host); @@ -3359,9 +3322,9 @@ int dw_mci_runtime_resume(struct device *dev) return 0; err: - if (host->cur_slot && - (mmc_can_gpio_cd(host->cur_slot->mmc) || - !mmc_card_is_removable(host->cur_slot->mmc))) + if (host->slot && + (mmc_can_gpio_cd(host->slot->mmc) || + !mmc_card_is_removable(host->slot->mmc))) clk_disable_unprepare(host->biu_clk); return ret; |