static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; /* * Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. */ if (host->clock <= 100 * 1000 * 1000 || !((ios.timing == MMC_TIMING_MMC_HS200) || (ios.timing == MMC_TIMING_UHS_SDR104))) return 0; retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) return rc; phase = 0; do { /* Set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; rc = mmc_send_tuning(mmc, opcode, NULL); if (!rc) { /* Tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); } } while (++phase < ARRAY_SIZE(tuned_phases)); if (tuned_phase_cnt) { rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) return rc; else phase = rc; /* * Finally set the selected phase in delay * line hw block. */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } return rc; }
static int msmsdcc_probe(struct platform_device *pdev) { struct mmc_platform_data *plat = pdev->dev.platform_data; struct msmsdcc_host *host; struct mmc_host *mmc; struct resource *irqres = NULL; struct resource *memres = NULL; struct resource *dmares = NULL; int ret; int i; /* must have platform data */ if (!plat) { pr_err("%s: Platform data not available\n", __func__); ret = -EINVAL; goto out; } if (pdev->id < 1 || pdev->id > 4) return -EINVAL; if (pdev->resource == NULL || pdev->num_resources < 3) { pr_err("%s: Invalid resource\n", __func__); return -ENXIO; } for (i = 0; i < pdev->num_resources; i++) { if (pdev->resource[i].flags & IORESOURCE_MEM) memres = &pdev->resource[i]; if (pdev->resource[i].flags & IORESOURCE_IRQ) irqres = &pdev->resource[i]; if (pdev->resource[i].flags & IORESOURCE_DMA) dmares = &pdev->resource[i]; } if (!irqres || !memres) { pr_err("%s: Invalid resource\n", __func__); return -ENXIO; } /* * Setup our host structure */ mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; goto out; } host = mmc_priv(mmc); host->pdev_id = pdev->id; host->plat = plat; host->mmc = mmc; host->curr.cmd = NULL; host->base = ioremap(memres->start, PAGE_SIZE); if (!host->base) { ret = -ENOMEM; goto host_free; } host->irqres = irqres; host->memres = memres; host->dmares = dmares; spin_lock_init(&host->lock); #ifdef CONFIG_MMC_EMBEDDED_SDIO if (plat->embedded_sdio) mmc_set_embedded_sdio_data(mmc, &plat->embedded_sdio->cis, &plat->embedded_sdio->cccr, plat->embedded_sdio->funcs, plat->embedded_sdio->num_funcs); #endif #ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ INIT_WORK(&host->resume_task, do_resume_work); #endif tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet, (unsigned long)host); /* * Setup DMA */ ret = msmsdcc_init_dma(host); if (ret) goto ioremap_free; /* * Setup main peripheral bus clock */ host->pclk = clk_get(&pdev->dev, "sdc_pclk"); if (IS_ERR(host->pclk)) { ret = PTR_ERR(host->pclk); goto dma_free; } ret = clk_enable(host->pclk); if (ret) goto pclk_put; host->pclk_rate = clk_get_rate(host->pclk); /* * Setup SDC MMC clock */ host->clk = clk_get(&pdev->dev, "sdc_clk"); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); goto pclk_disable; } ret = clk_enable(host->clk); if (ret) goto clk_put; ret = clk_set_rate(host->clk, msmsdcc_fmin); if (ret) { pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); goto clk_disable; } host->clk_rate = clk_get_rate(host->clk); host->clks_on = 1; /* * Setup MMC host structure */ mmc->ops = &msmsdcc_ops; mmc->f_min = msmsdcc_fmin; mmc->f_max = msmsdcc_fmax; mmc->ocr_avail = plat->ocr_mask; mmc->caps |= plat->mmc_bus_width; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; #ifdef CONFIG_MMC_MSM_SDIO_SUPPORT mmc->caps |= MMC_CAP_SDIO_IRQ; #endif mmc->max_phys_segs = NR_SG; mmc->max_hw_segs = NR_SG; mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */ mmc->max_blk_count = 65536; mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ mmc->max_seg_size = mmc->max_req_size; writel(0, host->base + MMCIMASK0); writel(MCI_CLEAR_STATIC_MASK, host->base + MMCICLEAR); /* Delay needed (MMCIMASK0 was just written above) */ msmsdcc_delay(host); writel(MCI_IRQENABLE, host->base + MMCIMASK0); host->mci_irqenable = MCI_IRQENABLE; /* * Setup card detect change */ if (plat->status_irq) { ret = request_irq(plat->status_irq, msmsdcc_platform_status_irq, IRQF_SHARED | plat->irq_flags, DRIVER_NAME " (slot)", host); if (ret) { pr_err("Unable to get slot IRQ %d (%d)\n", plat->status_irq, ret); goto clk_disable; } } else if (plat->register_status_notify) { plat->register_status_notify(msmsdcc_status_notify_cb, host); } else if (!plat->status) pr_err("%s: No card detect facilities available\n", mmc_hostname(mmc)); if (plat->status) { host->oldstat = host->plat->status(mmc_dev(host->mmc)); host->eject = !host->oldstat; } if (host->plat->sdiowakeup_irq) { ret = request_irq(plat->sdiowakeup_irq, msmsdcc_platform_sdiowakeup_irq, IRQF_SHARED | IRQF_TRIGGER_FALLING, DRIVER_NAME "sdiowakeup", host); if (ret) { pr_err("Unable to get sdio wakeup IRQ %d (%d)\n", plat->sdiowakeup_irq, ret); goto platform_irq_free; } else { set_irq_wake(host->plat->sdiowakeup_irq, 1); disable_irq(host->plat->sdiowakeup_irq); } } ret = request_irq(irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto sdiowakeup_irq_free; ret = request_irq(irqres->end, msmsdcc_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); if (ret) goto irq_free; mmc_set_drvdata(pdev, mmc); mmc_add_host(mmc); #ifdef CONFIG_HAS_EARLYSUSPEND host->early_suspend.suspend = msmsdcc_early_suspend; host->early_suspend.resume = msmsdcc_late_resume; host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; register_early_suspend(&host->early_suspend); #endif pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", mmc_hostname(mmc), (unsigned long long)memres->start, (unsigned int) irqres->start, (unsigned int) plat->status_irq, host->dma.channel); pr_info("%s: 8 bit data mode %s\n", mmc_hostname(mmc), (mmc->caps & MMC_CAP_8_BIT_DATA ? "enabled" : "disabled")); pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc), (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); pr_info("%s: polling status mode %s\n", mmc_hostname(mmc), (mmc->caps & MMC_CAP_NEEDS_POLL ? "enabled" : "disabled")); pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); pr_info("%s: Power save feature enable = %d\n", mmc_hostname(mmc), msmsdcc_pwrsave); if (host->dma.channel != -1) { pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", mmc_hostname(mmc), host->dma.cmd_busaddr, host->dma.cmdptr_busaddr); } else pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc)); #if defined(CONFIG_DEBUG_FS) msmsdcc_dbg_createhost(host); #endif if (!plat->status_irq) { ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp); if (ret) goto irq_free; } return 0; irq_free: free_irq(irqres->start, host); sdiowakeup_irq_free: if (plat->sdiowakeup_irq) { set_irq_wake(host->plat->sdiowakeup_irq, 0); free_irq(plat->sdiowakeup_irq, host); } platform_irq_free: if (plat->status_irq) free_irq(plat->status_irq, host); clk_disable: clk_disable(host->clk); clk_put: clk_put(host->clk); pclk_disable: clk_disable(host->pclk); pclk_put: clk_put(host->pclk); dma_free: dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), host->dma.nc, host->dma.nc_busaddr); ioremap_free: iounmap(host->base); host_free: mmc_free_host(mmc); out: return ret; }
static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) { struct msmsdcc_nc_dmadata *nc; dmov_box *box; uint32_t rows; uint32_t crci; unsigned int n; int i, rc; struct scatterlist *sg = data->sg; rc = validate_dma(host, data); if (rc) return rc; host->dma.sg = data->sg; host->dma.num_ents = data->sg_len; BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ nc = host->dma.nc; if (host->pdev_id == 1) crci = MSMSDCC_CRCI_SDC1; else if (host->pdev_id == 2) crci = MSMSDCC_CRCI_SDC2; else if (host->pdev_id == 3) crci = MSMSDCC_CRCI_SDC3; else if (host->pdev_id == 4) crci = MSMSDCC_CRCI_SDC4; else { host->dma.sg = NULL; host->dma.num_ents = 0; return -ENOENT; } if (data->flags & MMC_DATA_READ) host->dma.dir = DMA_FROM_DEVICE; else host->dma.dir = DMA_TO_DEVICE; /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */ host->curr.user_pages = 0; box = &nc->cmd[0]; for (i = 0; i < host->dma.num_ents; i++) { box->cmd = CMD_MODE_BOX; /* Initialize sg dma address */ sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) + sg->offset; if (i == (host->dma.num_ents - 1)) box->cmd |= CMD_LC; rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : (sg_dma_len(sg) / MCI_FIFOSIZE) ; if (data->flags & MMC_DATA_READ) { box->src_row_addr = msmsdcc_fifo_addr(host); box->dst_row_addr = sg_dma_address(sg); box->src_dst_len = (MCI_FIFOSIZE << 16) | (MCI_FIFOSIZE); box->row_offset = MCI_FIFOSIZE; box->num_rows = rows * ((1 << 16) + 1); box->cmd |= CMD_SRC_CRCI(crci); } else { box->src_row_addr = sg_dma_address(sg); box->dst_row_addr = msmsdcc_fifo_addr(host); box->src_dst_len = (MCI_FIFOSIZE << 16) | (MCI_FIFOSIZE); box->row_offset = (MCI_FIFOSIZE << 16); box->num_rows = rows * ((1 << 16) + 1); box->cmd |= CMD_DST_CRCI(crci); } box++; sg++; } /* location of command block must be 64 bit aligned */ BUG_ON(host->dma.cmd_busaddr & 0x07); nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); host->dma.hdr.complete_func = msmsdcc_dma_complete_func; n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); /* dsb inside dma_map_sg will write nc out to mem as well */ if (n != host->dma.num_ents) { pr_err("%s: Unable to map in all sg elements\n", mmc_hostname(host->mmc)); host->dma.sg = NULL; host->dma.num_ents = 0; return -ENOMEM; } return 0; }
static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmc_omap_slot *slot = mmc_priv(mmc); struct mmc_omap_host *host = slot->host; int i, dsor; int clk_enabled; mmc_omap_select_slot(slot, 0); dsor = mmc_omap_calc_divisor(mmc, ios); if (ios->vdd != slot->vdd) slot->vdd = ios->vdd; clk_enabled = 0; switch (ios->power_mode) { case MMC_POWER_OFF: mmc_omap_set_power(slot, 0, ios->vdd); break; case MMC_POWER_UP: /* Cannot touch dsor yet, just power up MMC */ mmc_omap_set_power(slot, 1, ios->vdd); goto exit; case MMC_POWER_ON: mmc_omap_fclk_enable(host, 1); clk_enabled = 1; dsor |= 1 << 11; break; } if (slot->bus_mode != ios->bus_mode) { if (slot->pdata->set_bus_mode != NULL) slot->pdata->set_bus_mode(mmc_dev(mmc), slot->id, ios->bus_mode); slot->bus_mode = ios->bus_mode; } /* On insanely high arm_per frequencies something sometimes * goes somehow out of sync, and the POW bit is not being set, * which results in the while loop below getting stuck. * Writing to the CON register twice seems to do the trick. */ for (i = 0; i < 2; i++) OMAP_MMC_WRITE(host, CON, dsor); slot->saved_con = dsor; if (ios->power_mode == MMC_POWER_ON) { /* worst case at 400kHz, 80 cycles makes 200 microsecs */ int usecs = 250; /* Send clock cycles, poll completion */ OMAP_MMC_WRITE(host, IE, 0); OMAP_MMC_WRITE(host, STAT, 0xffff); OMAP_MMC_WRITE(host, CMD, 1 << 7); while (usecs > 0 && (OMAP_MMC_READ(host, STAT) & 1) == 0) { udelay(1); usecs--; } OMAP_MMC_WRITE(host, STAT, 1); } exit: mmc_omap_release_slot(slot, clk_enabled); }
static irqreturn_t mmc_omap_irq(int irq, void *dev_id) { struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id; u16 status; int end_command; int end_transfer; int transfer_error, cmd_error; if (host->cmd == NULL && host->data == NULL) { status = OMAP_MMC_READ(host, STAT); dev_info(mmc_dev(host->slots[0]->mmc), "Spurious IRQ 0x%04x\n", status); if (status != 0) { OMAP_MMC_WRITE(host, STAT, status); OMAP_MMC_WRITE(host, IE, 0); } return IRQ_HANDLED; } end_command = 0; end_transfer = 0; transfer_error = 0; cmd_error = 0; while ((status = OMAP_MMC_READ(host, STAT)) != 0) { int cmd; OMAP_MMC_WRITE(host, STAT, status); if (host->cmd != NULL) cmd = host->cmd->opcode; else cmd = -1; #ifdef CONFIG_MMC_DEBUG dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ", status, cmd); mmc_omap_report_irq(status); printk("\n"); #endif if (host->total_bytes_left) { if ((status & OMAP_MMC_STAT_A_FULL) || (status & OMAP_MMC_STAT_END_OF_DATA)) mmc_omap_xfer_data(host, 0); if (status & OMAP_MMC_STAT_A_EMPTY) mmc_omap_xfer_data(host, 1); } if (status & OMAP_MMC_STAT_END_OF_DATA) end_transfer = 1; if (status & OMAP_MMC_STAT_DATA_TOUT) { dev_dbg(mmc_dev(host->mmc), "data timeout (CMD%d)\n", cmd); if (host->data) { host->data->error = -ETIMEDOUT; transfer_error = 1; } } if (status & OMAP_MMC_STAT_DATA_CRC) { if (host->data) { host->data->error = -EILSEQ; dev_dbg(mmc_dev(host->mmc), "data CRC error, bytes left %d\n", host->total_bytes_left); transfer_error = 1; } else { dev_dbg(mmc_dev(host->mmc), "data CRC error\n"); } } if (status & OMAP_MMC_STAT_CMD_TOUT) { /* Timeouts are routine with some commands */ if (host->cmd) { struct mmc_omap_slot *slot = host->current_slot; if (slot == NULL || !mmc_omap_cover_is_open(slot)) dev_err(mmc_dev(host->mmc), "command timeout (CMD%d)\n", cmd); host->cmd->error = -ETIMEDOUT; end_command = 1; cmd_error = 1; } } if (status & OMAP_MMC_STAT_CMD_CRC) { if (host->cmd) { dev_err(mmc_dev(host->mmc), "command CRC error (CMD%d, arg 0x%08x)\n", cmd, host->cmd->arg); host->cmd->error = -EILSEQ; end_command = 1; cmd_error = 1; } else dev_err(mmc_dev(host->mmc), "command CRC error without cmd?\n"); } if (status & OMAP_MMC_STAT_CARD_ERR) { dev_dbg(mmc_dev(host->mmc), "ignoring card status error (CMD%d)\n", cmd); end_command = 1; } /* * NOTE: On 1610 the END_OF_CMD may come too early when * starting a write */ if ((status & OMAP_MMC_STAT_END_OF_CMD) && (!(status & OMAP_MMC_STAT_A_EMPTY))) { end_command = 1; } } if (cmd_error && host->data) { del_timer(&host->cmd_abort_timer); host->abort = 1; OMAP_MMC_WRITE(host, IE, 0); disable_irq_nosync(host->irq); schedule_work(&host->cmd_abort_work); return IRQ_HANDLED; } if (end_command) mmc_omap_cmd_done(host, host->cmd); if (host->data != NULL) { if (transfer_error) mmc_omap_xfer_done(host, host->data); else if (end_transfer) mmc_omap_end_of_data(host, host->data); } return IRQ_HANDLED; }
static int sdhci_tegra_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct sdhci_tegra_soc_data *soc_data; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_tegra *tegra_host; struct clk *clk; int rc; match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); if (!match) return -EINVAL; soc_data = match->data; host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*tegra_host)); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); tegra_host = sdhci_pltfm_priv(pltfm_host); tegra_host->ddr_signaling = false; tegra_host->pad_calib_required = false; tegra_host->pad_control_available = false; tegra_host->soc_data = soc_data; if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) { rc = tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host); if (rc == 0) host->mmc_host_ops.start_signal_voltage_switch = sdhci_tegra_start_signal_voltage_switch; } /* Hook to periodically rerun pad calibration */ if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) host->mmc_host_ops.request = tegra_sdhci_request; host->mmc_host_ops.hs400_enhanced_strobe = tegra_sdhci_hs400_enhanced_strobe; rc = mmc_of_parse(host->mmc); if (rc) goto err_parse_dt; if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) host->mmc->caps |= MMC_CAP_1_8V_DDR; tegra_sdhci_parse_pad_autocal_dt(host); tegra_sdhci_parse_tap_and_trim(host); tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_OUT_HIGH); if (IS_ERR(tegra_host->power_gpio)) { rc = PTR_ERR(tegra_host->power_gpio); goto err_power_req; } clk = devm_clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { dev_err(mmc_dev(host->mmc), "clk err\n"); rc = PTR_ERR(clk); goto err_clk_get; } clk_prepare_enable(clk); pltfm_host->clk = clk; tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev, "sdhci"); if (IS_ERR(tegra_host->rst)) { rc = PTR_ERR(tegra_host->rst); dev_err(&pdev->dev, "failed to get reset control: %d\n", rc); goto err_rst_get; } rc = reset_control_assert(tegra_host->rst); if (rc) goto err_rst_get; usleep_range(2000, 4000); rc = reset_control_deassert(tegra_host->rst); if (rc) goto err_rst_get; usleep_range(2000, 4000); rc = sdhci_add_host(host); if (rc) goto err_add_host; return 0; err_add_host: reset_control_assert(tegra_host->rst); err_rst_get: clk_disable_unprepare(pltfm_host->clk); err_clk_get: err_power_req: err_parse_dt: sdhci_pltfm_free(pdev); return rc; }
static int sdhci_pxav3_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; const struct of_device_id *match; int ret; struct clk *clk; pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL); if (!pxa) return -ENOMEM; host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, 0); if (IS_ERR(host)) return PTR_ERR(host); /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) { ret = armada_38x_quirks(pdev, host); if (ret < 0) goto err_clk_get; ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info()); if (ret < 0) goto err_mbus_win; } pltfm_host = sdhci_priv(host); pltfm_host->priv = pxa; clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) { dev_err(dev, "failed to get io clock\n"); ret = PTR_ERR(clk); goto err_clk_get; } pltfm_host->clk = clk; clk_prepare_enable(clk); match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); if (match) { ret = mmc_of_parse(host->mmc); if (ret) goto err_of_parse; sdhci_get_of_property(pdev); pdata = pxav3_get_mmc_pdata(dev); } else if (pdata) { /* on-chip device */ if (pdata->flags & PXA_FLAG_CARD_PERMANENT) host->mmc->caps |= MMC_CAP_NONREMOVABLE; /* If slot design supports 8 bit data, indicate this to MMC. */ if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) host->mmc->caps |= MMC_CAP_8_BIT_DATA; if (pdata->quirks) host->quirks |= pdata->quirks; if (pdata->quirks2) host->quirks2 |= pdata->quirks2; if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; if (pdata->host_caps2) host->mmc->caps2 |= pdata->host_caps2; if (pdata->pm_caps) host->mmc->pm_caps |= pdata->pm_caps; if (gpio_is_valid(pdata->ext_cd_gpio)) { ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio, 0); if (ret) { dev_err(mmc_dev(host->mmc), "failed to allocate card detect gpio\n"); goto err_cd_req; } } } pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, 1); ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "failed to add host\n"); goto err_add_host; } platform_set_drvdata(pdev, host); if (host->mmc->pm_caps & MMC_PM_KEEP_POWER) { device_init_wakeup(&pdev->dev, 1); host->mmc->pm_flags |= MMC_PM_WAKE_SDIO_IRQ; } else { device_init_wakeup(&pdev->dev, 0); } pm_runtime_put_autosuspend(&pdev->dev); return 0; err_add_host: pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); err_of_parse: err_cd_req: clk_disable_unprepare(clk); err_clk_get: err_mbus_win: sdhci_pltfm_free(pdev); return ret; }
/** * mmc_init_queue - initialise a queue structure. * @mq: mmc queue * @card: mmc card to attach this queue * @lock: queue lock * @subname: partition subname * * Initialise a MMC card request queue. */ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock, const char *subname) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; int ret; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); if (!mq->queue) return -ENOMEM; mq->queue->queuedata = mq; mq->req = NULL; blk_queue_prep_rq(mq->queue, mmc_prep_request); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); if (mmc_can_erase(card)) mmc_queue_setup_discard(mq->queue, card); #ifdef CONFIG_MMC_BLOCK_BOUNCE if (host->max_segs == 1) { unsigned int bouncesz; bouncesz = MMC_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; if (bouncesz > (host->max_blk_count * 512)) bouncesz = host->max_blk_count * 512; if (bouncesz > 512) { mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mq->bounce_buf) { printk(KERN_WARNING "%s: unable to " "allocate bounce buffer\n", mmc_card_name(card)); } } if (mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); blk_queue_max_hw_sectors(mq->queue, bouncesz / 512); blk_queue_max_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); mq->sg = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, 1); mq->bounce_sg = kmalloc(sizeof(struct scatterlist) * bouncesz / 512, GFP_KERNEL); if (!mq->bounce_sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->bounce_sg, bouncesz / 512); } } #endif if (!mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_hw_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_segments(mq->queue, host->max_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, host->max_segs); } sema_init(&mq->thread_sem, 1); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s", host->index, subname ? subname : ""); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); goto free_bounce_sg; } return 0; free_bounce_sg: if (mq->bounce_sg) kfree(mq->bounce_sg); mq->bounce_sg = NULL; cleanup_queue: if (mq->sg) kfree(mq->sg); mq->sg = NULL; if (mq->bounce_buf) kfree(mq->bounce_buf); mq->bounce_buf = NULL; blk_cleanup_queue(mq->queue); return ret; }
static int msm_find_most_appropriate_phase(struct sdhci_host *host, u8 *phase_table, u8 total_phases) { int ret; u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} }; u8 phases_per_row[MAX_PHASES] = { 0 }; int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0; int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0; bool phase_0_found = false, phase_15_found = false; struct mmc_host *mmc = host->mmc; if (!total_phases || (total_phases > MAX_PHASES)) { dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n", mmc_hostname(mmc), total_phases); return -EINVAL; } for (cnt = 0; cnt < total_phases; cnt++) { ranges[row_index][col_index] = phase_table[cnt]; phases_per_row[row_index] += 1; col_index++; if ((cnt + 1) == total_phases) { continue; /* check if next phase in phase_table is consecutive or not */ } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) { row_index++; col_index = 0; } } if (row_index >= MAX_PHASES) return -EINVAL; /* Check if phase-0 is present in first valid window? */ if (!ranges[0][0]) { phase_0_found = true; phase_0_raw_index = 0; /* Check if cycle exist between 2 valid windows */ for (cnt = 1; cnt <= row_index; cnt++) { if (phases_per_row[cnt]) { for (i = 0; i < phases_per_row[cnt]; i++) { if (ranges[cnt][i] == 15) { phase_15_found = true; phase_15_raw_index = cnt; break; } } } } } /* If 2 valid windows form cycle then merge them as single window */ if (phase_0_found && phase_15_found) { /* number of phases in raw where phase 0 is present */ u8 phases_0 = phases_per_row[phase_0_raw_index]; /* number of phases in raw where phase 15 is present */ u8 phases_15 = phases_per_row[phase_15_raw_index]; if (phases_0 + phases_15 >= MAX_PHASES) /* * If there are more than 1 phase windows then total * number of phases in both the windows should not be * more than or equal to MAX_PHASES. */ return -EINVAL; /* Merge 2 cyclic windows */ i = phases_15; for (cnt = 0; cnt < phases_0; cnt++) { ranges[phase_15_raw_index][i] = ranges[phase_0_raw_index][cnt]; if (++i >= MAX_PHASES) break; } phases_per_row[phase_0_raw_index] = 0; phases_per_row[phase_15_raw_index] = phases_15 + phases_0; } for (cnt = 0; cnt <= row_index; cnt++) { if (phases_per_row[cnt] > curr_max) { curr_max = phases_per_row[cnt]; selected_row_index = cnt; } } i = (curr_max * 3) / 4; if (i) i--; ret = ranges[selected_row_index][i]; if (ret >= MAX_PHASES) { ret = -EINVAL; dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n", mmc_hostname(mmc), ret); } return ret; }
/** * mmc_init_queue - initialise a queue structure. * @mq: mmc queue * @card: mmc card to attach this queue * @lock: queue lock * * Initialise a MMC card request queue. */ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; int ret; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); if (!mq->queue) return -ENOMEM; mq->queue->queuedata = mq; mq->req = NULL; blk_queue_prep_rq(mq->queue, mmc_prep_request); #ifdef CONFIG_MMC_BLOCK_BOUNCE if (host->max_hw_segs == 1) { unsigned int bouncesz; bouncesz = MMC_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mq->bounce_buf) { printk(KERN_WARNING "%s: unable to allocate " "bounce buffer\n", mmc_card_name(card)); } else { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH); blk_queue_max_sectors(mq->queue, bouncesz / 512); blk_queue_max_phys_segments(mq->queue, bouncesz / 512); blk_queue_max_hw_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); mq->sg = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, 1); mq->bounce_sg = kmalloc(sizeof(struct scatterlist) * bouncesz / 512, GFP_KERNEL); if (!mq->bounce_sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->bounce_sg, bouncesz / 512); } } #endif if (!mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_sectors(mq->queue, host->max_req_size / 512); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, host->max_phys_segs); } init_MUTEX(&mq->thread_sem); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); goto free_bounce_sg; } return 0; free_bounce_sg: if (mq->bounce_sg) kfree(mq->bounce_sg); mq->bounce_sg = NULL; cleanup_queue: if (mq->sg) kfree(mq->sg); mq->sg = NULL; if (mq->bounce_buf) kfree(mq->bounce_buf); mq->bounce_buf = NULL; blk_cleanup_queue(mq->queue); return ret; }
static int __devinit tegra_sdhci_probe(struct platform_device *pdev) { int rc; struct tegra_sdhci_platform_data *plat; struct sdhci_host *sdhci; struct tegra_sdhci_host *host; struct resource *res; int irq; void __iomem *ioaddr; plat = pdev->dev.platform_data; if (plat == NULL) return -ENXIO; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) return -ENODEV; irq = res->start; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) return -ENODEV; ioaddr = ioremap(res->start, res->end - res->start); sdhci = sdhci_alloc_host(&pdev->dev, sizeof(struct tegra_sdhci_host)); if (IS_ERR(sdhci)) { rc = PTR_ERR(sdhci); goto err_unmap; } host = sdhci_priv(sdhci); host->sdhci = sdhci; host->plat = plat; #ifdef CONFIG_MMC_EMBEDDED_SDIO if (plat->mmc_data.embedded_sdio) mmc_set_embedded_sdio_data(sdhci->mmc, &plat->mmc_data.embedded_sdio->cis, &plat->mmc_data.embedded_sdio->cccr, plat->mmc_data.embedded_sdio->funcs, plat->mmc_data.embedded_sdio->num_funcs); #endif host->clk = clk_get(&pdev->dev, plat->clk_id); if (IS_ERR(host->clk)) { rc = PTR_ERR(host->clk); goto err_free_host; } rc = clk_enable(host->clk); if (rc != 0) goto err_clkput; host->clk_enabled = 1; sdhci->hw_name = "tegra"; sdhci->ops = &tegra_sdhci_ops; sdhci->irq = irq; sdhci->ioaddr = ioaddr; sdhci->version = SDHCI_SPEC_200; sdhci->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP | SDHCI_QUIRK_BROKEN_WRITE_PROTECT | SDHCI_QUIRK_BROKEN_CTRL_HISPD | SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_8_BIT_DATA | SDHCI_QUIRK_NO_VERSION_REG | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_NO_SDIO_IRQ; if (plat->force_hs != 0) sdhci->quirks |= SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE; if (plat->rt_disable != 0) sdhci->quirks |= SDHCI_QUIRK_RUNTIME_DISABLE; sdhci->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY; if (plat->mmc_data.built_in) sdhci->mmc->pm_flags = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY; rc = sdhci_add_host(sdhci); if (rc) goto err_clk_disable; platform_set_drvdata(pdev, host); if (plat->cd_gpio != -1) { rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(sdhci->mmc), sdhci); if (rc) goto err_remove_host; } else if (plat->mmc_data.register_status_notify) { plat->mmc_data.register_status_notify(sdhci_status_notify_cb, sdhci); } if (plat->mmc_data.status) { sdhci->card_present = host->plat->mmc_data.status(mmc_dev(sdhci->mmc)); } if (plat->board_probe) plat->board_probe(pdev->id, sdhci->mmc); printk(KERN_INFO "sdhci%d: initialized irq %d ioaddr %p\n", pdev->id, sdhci->irq, sdhci->ioaddr); return 0; err_remove_host: sdhci_remove_host(sdhci, 1); err_clk_disable: clk_disable(host->clk); err_clkput: clk_put(host->clk); err_free_host: if (sdhci) sdhci_free_host(sdhci); err_unmap: iounmap(sdhci->ioaddr); return rc; }
int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock, const char *subname) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; int ret; struct mmc_queue_req *mqrq_cur = &mq->mqrq[0]; struct mmc_queue_req *mqrq_prev = &mq->mqrq[1]; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = *mmc_dev(host)->dma_mask; mq->card = card; 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; blk_queue_prep_rq(mq->queue, mmc_prep_request); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); if (mmc_can_erase(card)) mmc_queue_setup_discard(mq->queue, card); #ifdef CONFIG_MMC_BLOCK_BOUNCE if (host->max_segs == 1) { unsigned int bouncesz; if(mmc_card_sd(card)) { bouncesz = SD_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; if (bouncesz > (host->max_blk_count * 512)) bouncesz = host->max_blk_count * 512; sd_buffer_pre_alloc(); mqrq_cur->bounce_buf = (char *)sd_bounce_buffer_cur; mqrq_prev->bounce_buf = (char *)sd_bounce_buffer_prev; } else { bouncesz = MMC_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; if (bouncesz > (host->max_blk_count * 512)) bouncesz = host->max_blk_count * 512; if (bouncesz > 512) { mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mqrq_cur->bounce_buf) { pr_warning("%s: unable to " "allocate bounce cur buffer\n", mmc_card_name(card)); } mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mqrq_prev->bounce_buf) { pr_warning("%s: unable to " "allocate bounce prev buffer\n", mmc_card_name(card)); kfree(mqrq_cur->bounce_buf); mqrq_cur->bounce_buf = NULL; } } } if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); blk_queue_max_hw_sectors(mq->queue, bouncesz / 512); blk_queue_max_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); mqrq_cur->sg = mmc_alloc_sg(1, &ret); if (ret) goto cleanup_queue; mqrq_cur->bounce_sg = mmc_alloc_sg(bouncesz / 512, &ret); if (ret) goto cleanup_queue; mqrq_prev->sg = mmc_alloc_sg(1, &ret); if (ret) goto cleanup_queue; mqrq_prev->bounce_sg = mmc_alloc_sg(bouncesz / 512, &ret); if (ret) goto cleanup_queue; } } #endif if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_hw_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_segments(mq->queue, host->max_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret); if (ret) goto cleanup_queue; mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret); if (ret) goto cleanup_queue; } sema_init(&mq->thread_sem, 1); if(mmc_card_sd(card)) mq->thread = kthread_run(sd_queue_thread, mq, "sd-qd"); else mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s", host->index, subname ? subname : ""); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); goto free_bounce_sg; } return 0; free_bounce_sg: kfree(mqrq_cur->bounce_sg); mqrq_cur->bounce_sg = NULL; kfree(mqrq_prev->bounce_sg); mqrq_prev->bounce_sg = NULL; cleanup_queue: kfree(mqrq_cur->sg); mqrq_cur->sg = NULL; if(!mmc_card_sd(card)) { kfree(mqrq_cur->bounce_buf); } mqrq_cur->bounce_buf = NULL; kfree(mqrq_prev->sg); mqrq_prev->sg = NULL; if(!mmc_card_sd(card)) { kfree(mqrq_prev->bounce_buf); } mqrq_prev->bounce_buf = NULL; blk_cleanup_queue(mq->queue); return ret; }
static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; int phase; u8 tuned_phase_cnt = 0; int rc = 0, longest_range = 0; int start = -1, end = 0, tuning_value = -1, range = 0; u16 clock_setting; struct mmc_host *mmc = host->mmc; clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING); clock_setting &= ~0x3fff; retry: phase = 0; tuned_phase_cnt = 0; do { sdhci_writel(host, clock_setting | phase, SDHCI_CLK_DELAY_SETTING); if (!mmc_send_tuning(mmc, opcode, NULL)) { /* Tuning is successful at this tuning point */ tuned_phase_cnt++; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); if (start == -1) start = phase; end = phase; range++; if (phase == (SIRF_TUNING_COUNT - 1) && range > longest_range) tuning_value = (start + end) / 2; } else { dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n", mmc_hostname(mmc), phase); if (range > longest_range) { tuning_value = (start + end) / 2; longest_range = range; } start = -1; end = range = 0; } } while (++phase < SIRF_TUNING_COUNT); if (tuned_phase_cnt && tuning_value > 0) { /* * Finally set the selected phase in delay * line hw block. */ phase = tuning_value; sdhci_writel(host, clock_setting | phase, SDHCI_CLK_DELAY_SETTING); dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } return rc; }
/* * Generic MMC request handler. This is called for any queue on a * particular host. When the host is not busy, we look for a request * 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) { struct mmc_queue *mq = q->queuedata; struct request *req; int ret; #if 0 if (!mq) { #else //插着USB线(充电姿态),拔插卡,有偶尔死机现象。出现mq->thread为空的现象;modifyed by xbw if (!mq ||!mq->thread) { #endif printk(KERN_ERR "MMC: killing requests for dead queue\n"); while ((req = elv_next_request(q)) != NULL) { do { ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); } while (ret); } return; } if (!mq->req) wake_up_process(mq->thread); } /** * mmc_init_queue - initialise a queue structure. * @mq: mmc queue * @card: mmc card to attach this queue * @lock: queue lock * * Initialise a MMC card request queue. */ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_ANY ; // BLK_BOUNCE_HIGH; int ret; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); if (!mq->queue) return -ENOMEM; mq->queue->queuedata = mq; mq->req = NULL; blk_queue_prep_rq(mq->queue, mmc_prep_request); #ifdef CONFIG_MMC_BLOCK_BOUNCE if (host->max_hw_segs == 1) { unsigned int bouncesz; bouncesz = MMC_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mq->bounce_buf) { printk(KERN_WARNING "%s: unable to allocate " "bounce buffer\n", mmc_card_name(card)); } else { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH); blk_queue_max_sectors(mq->queue, bouncesz / 512); blk_queue_max_phys_segments(mq->queue, bouncesz / 512); blk_queue_max_hw_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); mq->sg = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, 1); mq->bounce_sg = kmalloc(sizeof(struct scatterlist) * bouncesz / 512, GFP_KERNEL); if (!mq->bounce_sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->bounce_sg, bouncesz / 512); } } #endif if (!mq->bounce_buf) { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_sectors(mq->queue, host->max_req_size / 512); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } sg_init_table(mq->sg, host->max_phys_segs); } init_MUTEX(&mq->thread_sem); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); goto free_bounce_sg; } return 0; free_bounce_sg: if (mq->bounce_sg) kfree(mq->bounce_sg); mq->bounce_sg = NULL; cleanup_queue: if (mq->sg) kfree(mq->sg); mq->sg = NULL; if (mq->bounce_buf) kfree(mq->bounce_buf); mq->bounce_buf = NULL; blk_cleanup_queue(mq->queue); return ret; } void mmc_cleanup_queue(struct mmc_queue *mq) { struct request_queue *q = mq->queue; unsigned long flags; /* Mark that we should start throwing out stragglers */ spin_lock_irqsave(q->queue_lock, flags); q->queuedata = NULL; spin_unlock_irqrestore(q->queue_lock, flags); /* Make sure the queue isn't suspended, as that will deadlock */ mmc_queue_resume(mq); /* Then terminate our worker thread */ kthread_stop(mq->thread); if (mq->bounce_sg) kfree(mq->bounce_sg); mq->bounce_sg = NULL; kfree(mq->sg); mq->sg = NULL; if (mq->bounce_buf) kfree(mq->bounce_buf); mq->bounce_buf = NULL; blk_cleanup_queue(mq->queue); mq->card = NULL; } EXPORT_SYMBOL(mmc_cleanup_queue); /** * mmc_queue_suspend - suspend a MMC request queue * @mq: MMC queue to suspend * * Stop the block request queue, and wait for our thread to * complete any outstanding requests. This ensures that we * won't suspend while a request is being processed. */ void mmc_queue_suspend(struct mmc_queue *mq) { struct request_queue *q = mq->queue; unsigned long flags; if (!(mq->flags & MMC_QUEUE_SUSPENDED)) { mq->flags |= MMC_QUEUE_SUSPENDED; spin_lock_irqsave(q->queue_lock, flags); blk_stop_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); down(&mq->thread_sem); } } /** * mmc_queue_resume - resume a previously suspended MMC request queue * @mq: MMC queue to resume */ void mmc_queue_resume(struct mmc_queue *mq) { struct request_queue *q = mq->queue; unsigned long flags; if (mq->flags & MMC_QUEUE_SUSPENDED) { mq->flags &= ~MMC_QUEUE_SUSPENDED; up(&mq->thread_sem); spin_lock_irqsave(q->queue_lock, flags); blk_start_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } } static void copy_sg(struct scatterlist *dst, unsigned int dst_len, struct scatterlist *src, unsigned int src_len) { unsigned int chunk; char *dst_buf, *src_buf; unsigned int dst_size, src_size; dst_buf = NULL; src_buf = NULL; dst_size = 0; src_size = 0; while (src_len) { BUG_ON(dst_len == 0); if (dst_size == 0) { dst_buf = sg_virt(dst); dst_size = dst->length; } if (src_size == 0) { src_buf = sg_virt(src); src_size = src->length; } chunk = min(dst_size, src_size); memcpy(dst_buf, src_buf, chunk); dst_buf += chunk; src_buf += chunk; dst_size -= chunk; src_size -= chunk; if (dst_size == 0) { dst++; dst_len--; } if (src_size == 0) { src++; src_len--; } } }
static void msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct msmsdcc_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; int rc; if (ios->clock) { if (!host->clks_on) { clk_enable(host->pclk); clk_enable(host->clk); host->clks_on = 1; } if (ios->clock != host->clk_rate) { rc = clk_set_rate(host->clk, ios->clock); if (rc < 0) printk(KERN_ERR "Error setting clock rate (%d)\n", rc); else host->clk_rate = ios->clock; } clk |= MCI_CLK_ENABLE; } if (ios->bus_width == MMC_BUS_WIDTH_4) clk |= (2 << 10); /* Set WIDEBUS */ if (ios->clock > 400000 && msmsdcc_pwrsave) clk |= (1 << 9); /* PWRSAVE */ clk |= (1 << 12); /* FLOW_ENA */ clk |= (1 << 15); /* feedback clock */ if (host->plat->translate_vdd) pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); switch (ios->power_mode) { case MMC_POWER_OFF: htc_pwrsink_set(PWRSINK_SDCARD, 0); break; case MMC_POWER_UP: pwr |= MCI_PWR_UP; break; case MMC_POWER_ON: htc_pwrsink_set(PWRSINK_SDCARD, 100); pwr |= MCI_PWR_ON; break; } if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) pwr |= MCI_OD; writel(clk, host->base + MMCICLOCK); if (host->pwr != pwr) { host->pwr = pwr; writel(pwr, host->base + MMCIPOWER); } if (!(clk & MCI_CLK_ENABLE) && host->clks_on) { clk_disable(host->clk); clk_disable(host->pclk); host->clks_on = 0; } }
/* Initialize the DLL (Programmable Delay Line) */ static int msm_init_cm_dll(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); int wait_cnt = 50; unsigned long flags; u32 config; spin_lock_irqsave(&host->lock, flags); /* * Make sure that clock is always enabled when DLL * tuning is in progress. Keeping PWRSAVE ON may * turn off the clock. */ config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config &= ~CORE_CLK_PWRSAVE; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); if (msm_host->use_14lpp_dll_reset) { config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config &= ~CORE_CK_OUT_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config |= CORE_DLL_CLOCK_DISABLE; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); } config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_RST; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_PDN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); msm_cm_dll_set_freq(host); if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk)) { u32 mclk_freq = 0; config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config &= CORE_FLL_CYCLE_CNT; if (config) mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8), clk_get_rate(msm_host->xo_clk)); else mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4), clk_get_rate(msm_host->xo_clk)); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config &= ~(0xFF << 10); config |= mclk_freq << 10; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); /* wait for 5us before enabling DLL clock */ udelay(5); } config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config &= ~CORE_DLL_RST; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config &= ~CORE_DLL_PDN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); if (msm_host->use_14lpp_dll_reset) { msm_cm_dll_set_freq(host); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config &= ~CORE_DLL_CLOCK_DISABLE; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); } config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_CK_OUT_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) & CORE_DLL_LOCK)) { /* max. wait for 50us sec for LOCK bit to be set */ if (--wait_cnt == 0) { dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n", mmc_hostname(mmc)); spin_unlock_irqrestore(&host->lock, flags); return -ETIMEDOUT; } udelay(1); } spin_unlock_irqrestore(&host->lock, flags); return 0; }
static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; struct clk *clk; int err; struct pltfm_imx_data *imx_data; clk = clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { dev_err(mmc_dev(host->mmc), "clk err\n"); return PTR_ERR(clk); } clk_enable(clk); pltfm_host->clk = clk; imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); if (!imx_data) { clk_disable(pltfm_host->clk); clk_put(pltfm_host->clk); return -ENOMEM; } pltfm_host->priv = imx_data; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; if (cpu_is_mx25() || cpu_is_mx35()) { /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; /* write_protect can't be routed to controller, use gpio */ sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; } if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())) imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; if (boarddata) { err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); if (err) { dev_warn(mmc_dev(host->mmc), "no write-protect pin available!\n"); boarddata->wp_gpio = err; } err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); if (err) { dev_warn(mmc_dev(host->mmc), "no card-detect pin available!\n"); goto no_card_detect_pin; } /* i.MX5x has issues to be researched */ if (!cpu_is_mx25() && !cpu_is_mx35()) goto not_supported; err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(host->mmc), host); if (err) { dev_warn(mmc_dev(host->mmc), "request irq error\n"); goto no_card_detect_irq; } imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP; /* Now we have a working card_detect again */ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; } return 0; no_card_detect_irq: gpio_free(boarddata->cd_gpio); no_card_detect_pin: boarddata->cd_gpio = err; not_supported: kfree(imx_data); return 0; }
static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); int tuning_seq_cnt = 3; u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; struct mmc_ios ios = host->mmc->ios; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); /* * Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. */ if (host->clock <= CORE_FREQ_100MHZ || !(ios.timing == MMC_TIMING_MMC_HS400 || ios.timing == MMC_TIMING_MMC_HS200 || ios.timing == MMC_TIMING_UHS_SDR104)) return 0; /* * For HS400 tuning in HS200 timing requires: * - select MCLK/2 in VENDOR_SPEC * - program MCLK to 400MHz (or nearest supported) in GCC */ if (host->flags & SDHCI_HS400_TUNING) { sdhci_msm_hc_select_mode(host); msm_set_clock_rate_for_bus_mode(host, ios.clock); host->flags &= ~SDHCI_HS400_TUNING; } retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) return rc; phase = 0; do { /* Set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; msm_host->saved_tuning_phase = phase; rc = mmc_send_tuning(mmc, opcode, NULL); if (!rc) { /* Tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); } } while (++phase < ARRAY_SIZE(tuned_phases)); if (tuned_phase_cnt) { rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) return rc; else phase = rc; /* * Finally set the selected phase in delay * line hw block. */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } if (!rc) msm_host->tuning_done = true; return rc; }
static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_tegra_autocal_offsets offsets = tegra_host->autocal_offsets; struct mmc_ios *ios = &host->mmc->ios; bool card_clk_enabled; u16 pdpu; u32 reg; int ret; switch (ios->timing) { case MMC_TIMING_UHS_SDR104: pdpu = offsets.pull_down_sdr104 << 8 | offsets.pull_up_sdr104; break; case MMC_TIMING_MMC_HS400: pdpu = offsets.pull_down_hs400 << 8 | offsets.pull_up_hs400; break; default: if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) pdpu = offsets.pull_down_1v8 << 8 | offsets.pull_up_1v8; else pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3; } tegra_sdhci_set_pad_autocal_offset(host, pdpu); card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); tegra_sdhci_configure_cal_pad(host, true); reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); reg |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START; sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); usleep_range(1, 2); /* 10 ms timeout */ ret = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_AUTO_CAL_STATUS, reg, !(reg & SDHCI_TEGRA_AUTO_CAL_ACTIVE), 1000, 10000); tegra_sdhci_configure_cal_pad(host, false); tegra_sdhci_configure_card_clk(host, card_clk_enabled); if (ret) { dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n"); if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) pdpu = offsets.pull_down_1v8_timeout << 8 | offsets.pull_up_1v8_timeout; else pdpu = offsets.pull_down_3v3_timeout << 8 | offsets.pull_up_3v3_timeout; /* Disable automatic calibration and use fixed offsets */ reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); reg &= ~SDHCI_AUTO_CAL_ENABLE; sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); tegra_sdhci_set_pad_autocal_offset(host, pdpu); } }
static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { struct mmc_host *mmc = host->mmc; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u16 ctrl_2; u32 config; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (uhs) { case MMC_TIMING_UHS_SDR12: ctrl_2 |= SDHCI_CTRL_UHS_SDR12; break; case MMC_TIMING_UHS_SDR25: ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: ctrl_2 |= SDHCI_CTRL_UHS_SDR50; break; case MMC_TIMING_MMC_HS400: case MMC_TIMING_MMC_HS200: case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104; break; case MMC_TIMING_UHS_DDR50: case MMC_TIMING_MMC_DDR52: ctrl_2 |= SDHCI_CTRL_UHS_DDR50; break; } /* * When clock frequency is less than 100MHz, the feedback clock must be * provided and DLL must not be used so that tuning can be skipped. To * provide feedback clock, the mode selection can be any value less * than 3'b011 in bits [2:0] of HOST CONTROL2 register. */ if (host->clock <= CORE_FREQ_100MHZ) { if (uhs == MMC_TIMING_MMC_HS400 || uhs == MMC_TIMING_MMC_HS200 || uhs == MMC_TIMING_UHS_SDR104) ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; /* * DLL is not required for clock <= 100MHz * Thus, make sure DLL it is disabled when not required */ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_RST; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_PDN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); /* * The DLL needs to be restored and CDCLP533 recalibrated * when the clock frequency is set back to 400MHz. */ msm_host->calibration_done = false; } dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); if (mmc->ios.timing == MMC_TIMING_MMC_HS400) sdhci_msm_hs400(host, &mmc->ios); }
static void mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) { struct mmc_data *data = req->data; int i, use_dma, block_size; unsigned sg_len; host->data = data; if (data == NULL) { OMAP_MMC_WRITE(host, BLEN, 0); OMAP_MMC_WRITE(host, NBLK, 0); OMAP_MMC_WRITE(host, BUF, 0); host->dma_in_use = 0; set_cmd_timeout(host, req); return; } block_size = data->blksz; OMAP_MMC_WRITE(host, NBLK, data->blocks - 1); OMAP_MMC_WRITE(host, BLEN, block_size - 1); set_data_timeout(host, req); /* cope with calling layer confusion; it issues "single * block" writes using multi-block scatterlists. */ sg_len = (data->blocks == 1) ? 1 : data->sg_len; /* Only do DMA for entire blocks */ use_dma = host->use_dma; if (use_dma) { for (i = 0; i < sg_len; i++) { if ((data->sg[i].length % block_size) != 0) { use_dma = 0; break; } } } host->sg_idx = 0; if (use_dma) { if (mmc_omap_get_dma_channel(host, data) == 0) { enum dma_data_direction dma_data_dir; if (data->flags & MMC_DATA_WRITE) dma_data_dir = DMA_TO_DEVICE; else dma_data_dir = DMA_FROM_DEVICE; host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, sg_len, dma_data_dir); host->total_bytes_left = 0; mmc_omap_prepare_dma(host, req->data); host->brs_received = 0; host->dma_done = 0; host->dma_in_use = 1; } else use_dma = 0; } /* Revert to PIO? */ if (!use_dma) { OMAP_MMC_WRITE(host, BUF, 0x1f1f); host->total_bytes_left = data->blocks * block_size; host->sg_len = sg_len; mmc_omap_sg_to_buf(host); host->dma_in_use = 0; } }
static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; 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; int qos_class = PM_QOS_CPUIDLE_BLOCK; pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL); if (!pxa) return -ENOMEM; host = sdhci_pltfm_init(pdev, NULL); if (IS_ERR(host)) { kfree(pxa); return PTR_ERR(host); } pltfm_host = sdhci_priv(host); pltfm_host->priv = pxa; clk = clk_get(dev, "PXA-SDHCLK"); if (IS_ERR(clk)) { dev_err(dev, "failed to get io clock\n"); ret = PTR_ERR(clk); goto err_clk_get; } pltfm_host->clk = clk; clk_prepare_enable(clk); host->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_32BIT_ADMA_SIZE | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); if (match) pdata = pxav3_get_mmc_pdata(dev); if (pdata) { pdata->qos_idle.name = mmc_hostname(host->mmc); pm_qos_add_request(&pdata->qos_idle, qos_class, PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE); /* If slot design supports 8 bit data, indicate this to MMC. */ if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) host->mmc->caps |= MMC_CAP_8_BIT_DATA; if (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING) host->mmc->caps2 |= MMC_CAP2_BUS_AUTO_CLK_GATE; if (pdata->flags & PXA_FLAG_DISABLE_PROBE_CDSCAN) host->mmc->caps2 |= MMC_CAP2_DISABLE_PROBE_CDSCAN; if (pdata->quirks) host->quirks |= pdata->quirks; if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; if (pdata->host_caps2) host->mmc->caps2 |= pdata->host_caps2; if (pdata->pm_caps) host->mmc->pm_caps |= pdata->pm_caps; if (pdata->cd_type != PXA_SDHCI_CD_HOST) host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; if (pdata->cd_type == PXA_SDHCI_CD_GPIO && gpio_is_valid(pdata->ext_cd_gpio)) { ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio); if (ret) { dev_err(mmc_dev(host->mmc), "failed to allocate card detect gpio\n"); goto err_cd_req; } } else if (pdata->cd_type == PXA_SDHCI_CD_PERMANENT) { /* on-chip device */ host->mmc->caps |= MMC_CAP_NONREMOVABLE; } else if (pdata->cd_type == PXA_SDHCI_CD_NONE) host->mmc->caps |= MMC_CAP_NEEDS_POLL; } host->quirks2 = SDHCI_QUIRK2_NO_CURRENT_LIMIT | SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_TIMEOUT_DIVIDE_4; host->ops = &pxav3_sdhci_ops; if (pdata && pdata->flags & PXA_FLAG_EN_PM_RUNTIME) { pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, 1); } #ifdef _MMC_SAFE_ACCESS_ mmc_is_available = 1; #endif ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "failed to add host\n"); if (pdata && pdata->flags & PXA_FLAG_EN_PM_RUNTIME) { pm_runtime_forbid(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); } goto err_add_host; } /* remove the caps that supported by the controller but not available * for certain platforms. */ if (pdata && pdata->host_caps_disable) host->mmc->caps &= ~(pdata->host_caps_disable); platform_set_drvdata(pdev, host); if (pdata && pdata->flags & PXA_FLAG_WAKEUP_HOST) { device_init_wakeup(&pdev->dev, 1); host->mmc->pm_flags |= MMC_PM_WAKE_SDIO_IRQ; } else device_init_wakeup(&pdev->dev, 0); #ifdef CONFIG_SD8XXX_RFKILL if (pdata && pdata->pmmc) *pdata->pmmc = host->mmc; #endif return 0; err_add_host: clk_disable_unprepare(clk); clk_put(clk); if (pdata) pm_qos_remove_request(&pdata->qos_idle); err_cd_req: mmc_gpio_free_cd(host->mmc); err_clk_get: sdhci_pltfm_free(pdev); kfree(pxa); return ret; }
static void mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) { u32 cmdreg; u32 resptype; u32 cmdtype; host->cmd = cmd; resptype = 0; cmdtype = 0; /* Our hardware needs to know exact type */ switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: break; case MMC_RSP_R1: case MMC_RSP_R1B: /* resp 1, 1b, 6, 7 */ resptype = 1; break; case MMC_RSP_R2: resptype = 2; break; case MMC_RSP_R3: resptype = 3; break; default: dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd)); break; } if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) { cmdtype = OMAP_MMC_CMDTYPE_ADTC; } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) { cmdtype = OMAP_MMC_CMDTYPE_BC; } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) { cmdtype = OMAP_MMC_CMDTYPE_BCR; } else { cmdtype = OMAP_MMC_CMDTYPE_AC; } cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12); if (host->current_slot->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdreg |= 1 << 6; if (cmd->flags & MMC_RSP_BUSY) cmdreg |= 1 << 11; if (host->data && !(host->data->flags & MMC_DATA_WRITE)) cmdreg |= 1 << 15; mod_timer(&host->cmd_abort_timer, jiffies + HZ/2); OMAP_MMC_WRITE(host, CTO, 200); OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); OMAP_MMC_WRITE(host, IE, OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | OMAP_MMC_STAT_END_OF_DATA); OMAP_MMC_WRITE(host, CMD, cmdreg); }
/** * mmc_init_queue - initialise a queue structure. * @mq: mmc queue * @card: mmc card to attach this queue * @lock: queue lock * * Initialise a MMC card request queue. */ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; int ret; struct mmc_queue_req *mqrq_cur = &mq->mqrq[0]; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = *mmc_dev(host)->dma_mask; mq->card = card; mq->queue = blk_init_queue(mmc_request, lock); if (!mq->queue) return -ENOMEM; memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur)); mq->mqrq_cur = mqrq_cur; mq->queue->queuedata = mq; blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); #ifdef CONFIG_MMC_BLOCK_BOUNCE if (host->max_hw_segs == 1) { unsigned int bouncesz; bouncesz = MMC_QUEUE_BOUNCESZ; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; if (bouncesz > host->max_seg_size) bouncesz = host->max_seg_size; if (bouncesz > (host->max_blk_count * 512)) bouncesz = host->max_blk_count * 512; if (bouncesz > 512) { mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mqrq_cur->bounce_buf) { printk(KERN_WARNING "%s: unable to " "allocate bounce curr buffer\n", mmc_card_name(card)); } } if (mqrq_cur->bounce_buf) { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); blk_queue_max_hw_sectors(mq->queue, bouncesz / 512); blk_queue_max_segments(mq->queue, bouncesz / 512); blk_queue_max_segment_size(mq->queue, bouncesz); mqrq_cur->sg = mmc_alloc_sg(1, &ret); if (ret) goto cleanup_queue; mqrq_cur->bounce_sg = mmc_alloc_sg(bouncesz / 512, &ret); if (ret) goto cleanup_queue; } } #endif if (!mqrq_cur->bounce_buf) { blk_queue_bounce_limit(mq->queue, limit); blk_queue_max_hw_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); mqrq_cur->sg = mmc_alloc_sg(host->max_phys_segs, &ret); if (ret) goto cleanup_queue; } init_MUTEX(&mq->thread_sem); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); if (IS_ERR(mq->thread)) { ret = PTR_ERR(mq->thread); goto free_bounce_sg; } return 0; free_bounce_sg: kfree(mqrq_cur->bounce_sg); mqrq_cur->bounce_sg = NULL; cleanup_queue: kfree(mqrq_cur->sg); mqrq_cur->sg = NULL; kfree(mqrq_cur->bounce_buf); mqrq_cur->bounce_buf = NULL; blk_cleanup_queue(mq->queue); return ret; }
static void msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct msmsdcc_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; int rc; DBG(host, "ios->clock = %u\n", ios->clock); if (ios->clock) { if (!host->clks_on) { clk_enable(host->pclk); clk_enable(host->clk); host->clks_on = 1; } if ((ios->clock < msmsdcc_fmax) && (ios->clock > msmsdcc_fmid)) ios->clock = msmsdcc_fmid; if (ios->clock != host->clk_rate) { rc = clk_set_rate(host->clk, ios->clock); if (rc < 0) { rc = clk_set_rate(host->clk, msmsdcc_temp); WARN_ON(rc < 0); host->clk_rate = msmsdcc_temp; } else host->clk_rate = ios->clock; } clk |= MCI_CLK_ENABLE; } if (ios->bus_width == MMC_BUS_WIDTH_8) clk |= MCI_CLK_WIDEBUS_8; else if (ios->bus_width == MMC_BUS_WIDTH_4) clk |= MCI_CLK_WIDEBUS_4; else clk |= MCI_CLK_WIDEBUS_1; if (ios->clock > 400000 && msmsdcc_pwrsave) clk |= MCI_CLK_PWRSAVE; clk |= MCI_CLK_FLOWENA; clk |= MCI_CLK_SELECTIN; /* feedback clock */ if (host->plat->translate_vdd) pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); switch (ios->power_mode) { case MMC_POWER_OFF: htc_pwrsink_set(PWRSINK_SDCARD, 0); break; case MMC_POWER_UP: pwr |= MCI_PWR_UP; break; case MMC_POWER_ON: htc_pwrsink_set(PWRSINK_SDCARD, 100); pwr |= MCI_PWR_ON; break; } if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) pwr |= MCI_OD; writel(clk, host->base + MMCICLOCK); if (host->pwr != pwr) { host->pwr = pwr; writel(pwr, host->base + MMCIPOWER); } if (!(clk & MCI_CLK_ENABLE) && host->clks_on) { clk_disable(host->clk); clk_disable(host->pclk); host->clks_on = 0; } }
int msmsdcc_probe(struct platform_device *pdev) { struct mmc_platform_data *plat = pdev->dev.platform_data; struct msmsdcc_host *host; struct mmc_host *mmc; struct resource *cmd_irqres = NULL; struct resource *pio_irqres = NULL; struct resource *stat_irqres = NULL; struct resource *memres = NULL; struct resource *dmares = NULL; int ret; /* must have platform data */ if (!plat) { printk(KERN_ERR "%s: Platform data not available\n", __func__); ret = -EINVAL; goto out; } if (pdev->id < 1 || pdev->id > 4) return -EINVAL; if (pdev->resource == NULL || pdev->num_resources < 2) { printk(KERN_ERR "%s: Invalid resource\n", __func__); return -ENXIO; } memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "cmd_irq"); pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "pio_irq"); stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq"); if (!cmd_irqres || !pio_irqres || !memres) { printk(KERN_ERR "%s: Invalid resource\n", __func__); return -ENXIO; } /* * Setup our host structure */ mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; goto out; } host = mmc_priv(mmc); host->pdev_id = pdev->id; host->plat = plat; host->mmc = mmc; host->cmdpoll = 1; host->base = ioremap(memres->start, PAGE_SIZE); if (!host->base) { ret = -ENOMEM; goto out; } host->cmd_irqres = cmd_irqres; host->pio_irqres = pio_irqres; host->memres = memres; host->dmares = dmares; spin_lock_init(&host->lock); #ifdef CONFIG_MMC_EMBEDDED_SDIO if (plat->embedded_sdio) mmc_set_embedded_sdio_data(mmc, &plat->embedded_sdio->cis, &plat->embedded_sdio->cccr, plat->embedded_sdio->funcs, plat->embedded_sdio->num_funcs); #endif #ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ INIT_WORK(&host->resume_task, do_resume_work); #endif /* * Setup DMA */ msmsdcc_init_dma(host); /* * Setup main peripheral bus clock */ host->pclk = clk_get(&pdev->dev, "sdc2_pclk"); if (IS_ERR(host->pclk)) { ret = PTR_ERR(host->pclk); goto host_free; } ret = clk_enable(host->pclk); if (ret) goto pclk_put; host->pclk_rate = clk_get_rate(host->pclk); /* * Setup SDC MMC clock */ host->clk = clk_get(&pdev->dev, "sdc2_clk"); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); goto pclk_disable; } ret = clk_enable(host->clk); if (ret) goto clk_put; ret = clk_set_rate(host->clk, msmsdcc_fmin); if (ret) { printk(KERN_ERR "%s: Clock rate set failed (%d)\n", __func__, ret); goto clk_disable; } host->clk_rate = clk_get_rate(host->clk); host->clks_on = 1; /* * Setup MMC host structure */ mmc->ops = &msmsdcc_ops; mmc->f_min = msmsdcc_fmin; mmc->f_max = msmsdcc_fmax; mmc->ocr_avail = plat->ocr_mask; if (msmsdcc_4bit) mmc->caps |= MMC_CAP_4_BIT_DATA; if (msmsdcc_sdioirq) mmc->caps |= MMC_CAP_SDIO_IRQ; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; mmc->max_phys_segs = NR_SG; mmc->max_hw_segs = NR_SG; mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */ mmc->max_blk_count = 65536; mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ mmc->max_seg_size = mmc->max_req_size; writel(0, host->base + MMCIMASK0); writel(0x5e007ff, host->base + MMCICLEAR); /* Add: 1 << 25 */ writel(MCI_IRQENABLE, host->base + MMCIMASK0); host->saved_irq0mask = MCI_IRQENABLE; /* * Setup card detect change */ memset(&host->timer, 0, sizeof(host->timer)); if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) { unsigned long irqflags = IRQF_SHARED | (stat_irqres->flags & IRQF_TRIGGER_MASK); host->stat_irq = stat_irqres->start; ret = request_irq(host->stat_irq, msmsdcc_platform_status_irq, irqflags, DRIVER_NAME " (slot)", host); if (ret) { printk(KERN_ERR "Unable to get slot IRQ %d (%d)\n", host->stat_irq, ret); goto clk_disable; } } else if (plat->register_status_notify) { plat->register_status_notify(msmsdcc_status_notify_cb, host); } else if (!plat->status) printk(KERN_ERR "%s: No card detect facilities available\n", mmc_hostname(mmc)); else { init_timer(&host->timer); host->timer.data = (unsigned long)host; host->timer.function = msmsdcc_check_status; host->timer.expires = jiffies + HZ; add_timer(&host->timer); } if (plat->status) { host->oldstat = host->plat->status(mmc_dev(host->mmc)); host->eject = !host->oldstat; } /* * Setup a command timer. We currently need this due to * some 'strange' timeout / error handling situations. */ init_timer(&host->command_timer); host->command_timer.data = (unsigned long) host; host->command_timer.function = msmsdcc_command_expired; ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto stat_irq_free; ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); if (ret) goto cmd_irq_free; mmc_set_drvdata(pdev, mmc); mmc_claim_host(mmc); printk(KERN_INFO "%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", mmc_hostname(mmc), (unsigned long long)memres->start, (unsigned int) cmd_irqres->start, (unsigned int) host->stat_irq, host->dma.channel); printk(KERN_INFO "%s: 4 bit data mode %s\n", mmc_hostname(mmc), (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); printk(KERN_INFO "%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); printk(KERN_INFO "%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); printk(KERN_INFO "%s: Power save feature enable = %d\n", mmc_hostname(mmc), msmsdcc_pwrsave); if (host->dma.channel != -1) { printk(KERN_INFO "%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); printk(KERN_INFO "%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", mmc_hostname(mmc), host->dma.cmd_busaddr, host->dma.cmdptr_busaddr); } else printk(KERN_INFO "%s: PIO transfer enabled\n", mmc_hostname(mmc)); if (host->timer.function) printk(KERN_INFO "%s: Polling status mode enabled\n", mmc_hostname(mmc)); #if defined(CONFIG_DEBUG_FS) msmsdcc_dbg_createhost(host); #endif return 0; cmd_irq_free: free_irq(cmd_irqres->start, host); stat_irq_free: if (host->stat_irq) free_irq(host->stat_irq, host); clk_disable: clk_disable(host->clk); clk_put: clk_put(host->clk); pclk_disable: clk_disable(host->pclk); pclk_put: clk_put(host->pclk); host_free: mmc_free_host(mmc); out: return ret; }
static void msmsdcc_dma_complete_tlet(unsigned long data) { struct msmsdcc_host *host = (struct msmsdcc_host *)data; unsigned long flags; struct mmc_request *mrq; spin_lock_irqsave(&host->lock, flags); mrq = host->curr.mrq; BUG_ON(!mrq); if (!(host->dma.result & DMOV_RSLT_VALID)) { pr_err("msmsdcc: Invalid DataMover result\n"); goto out; } if (host->dma.result & DMOV_RSLT_DONE) { host->curr.data_xfered = host->curr.xfer_size; } else { /* Error or flush */ if (host->dma.result & DMOV_RSLT_ERROR) pr_err("%s: DMA error (0x%.8x)\n", mmc_hostname(host->mmc), host->dma.result); if (host->dma.result & DMOV_RSLT_FLUSH) pr_err("%s: DMA channel flushed (0x%.8x)\n", mmc_hostname(host->mmc), host->dma.result); if (host->dma.err) { pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", host->dma.err->flush[0], host->dma.err->flush[1], host->dma.err->flush[2], host->dma.err->flush[3], host->dma.err->flush[4], host->dma.err->flush[5]); msmsdcc_reset_and_restore(host); } if (!mrq->data->error) mrq->data->error = -EIO; } dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); if (host->curr.user_pages) { struct scatterlist *sg = host->dma.sg; int i; for (i = 0; i < host->dma.num_ents; i++, sg++) flush_dcache_page(sg_page(sg)); } host->dma.sg = NULL; host->dma.busy = 0; if ((host->curr.got_dataend && host->curr.got_datablkend) || mrq->data->error) { if (mrq->data->error && !(host->curr.got_dataend && host->curr.got_datablkend)) { pr_info("%s: Worked around bug 1535304\n", mmc_hostname(host->mmc)); } /* * If we've already gotten our DATAEND / DATABLKEND * for this request, then complete it through here. */ msmsdcc_stop_data(host); if (!mrq->data->error) host->curr.data_xfered = host->curr.xfer_size; if (!mrq->data->stop || mrq->cmd->error) { host->curr.mrq = NULL; host->curr.cmd = NULL; mrq->data->bytes_xfered = host->curr.data_xfered; spin_unlock_irqrestore(&host->lock, flags); #ifdef CONFIG_MMC_MSM_PROG_DONE_SCAN if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) && (mrq->cmd->arg & 0x80000000)) { /* set the prog_scan in a cmd53.*/ host->prog_scan = 1; /* Send STOP to let the SDCC know to stop. */ writel(MCI_CSPM_MCIABORT, host->base + MMCICOMMAND); } #endif mmc_request_done(host->mmc, mrq); return; } else { #if defined (CONFIG_MACH_ACER_A1) while ((host->pdev_id == 1) && (mrq->data->flags & MMC_DATA_WRITE) && (gpio_get_value(SDCC1_DATA_0) == 0)) { udelay(5); } #endif msmsdcc_start_command(host, mrq->data->stop, 0); } } out: spin_unlock_irqrestore(&host->lock, flags); return; }
static void msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, unsigned int result, struct msm_dmov_errdata *err) { struct msmsdcc_dma_data *dma_data = container_of(cmd, struct msmsdcc_dma_data, hdr); struct msmsdcc_host *host = dma_data->host; unsigned long flags; struct mmc_request *mrq; spin_lock_irqsave(&host->lock, flags); mrq = host->curr.mrq; BUG_ON(!mrq); if (!(result & DMOV_RSLT_VALID)) { printk(KERN_ERR "msmsdcc: Invalid DataMover result\n"); goto out; } if (result & DMOV_RSLT_DONE) { host->curr.data_xfered = host->curr.xfer_size; } else { /* Error or flush */ if (result & DMOV_RSLT_ERROR) printk(KERN_ERR "%s: DMA error (0x%.8x)\n", mmc_hostname(host->mmc), result); if (result & DMOV_RSLT_FLUSH) printk(KERN_ERR "%s: DMA channel flushed (0x%.8x)\n", mmc_hostname(host->mmc), result); if (err) printk(KERN_ERR "Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", err->flush[0], err->flush[1], err->flush[2], err->flush[3], err->flush[4], err->flush[5]); if (!mrq->data->error) mrq->data->error = -EIO; } host->dma.busy = 0; dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); if (host->curr.user_pages) { struct scatterlist *sg = host->dma.sg; int i; for (i = 0; i < host->dma.num_ents; i++, sg++) flush_dcache_page(sg_page(sg)); } host->dma.sg = NULL; if ((host->curr.got_dataend && host->curr.got_datablkend) || mrq->data->error) { /* * If we've already gotten our DATAEND / DATABLKEND * for this request, then complete it through here. */ msmsdcc_stop_data(host); if (!mrq->data->error) host->curr.data_xfered = host->curr.xfer_size; if (!mrq->data->stop || mrq->cmd->error) { writel(0, host->base + MMCICOMMAND); host->curr.mrq = NULL; host->curr.cmd = NULL; mrq->data->bytes_xfered = host->curr.data_xfered; spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); return; } else msmsdcc_start_command(host, mrq->data->stop, 0); } out: spin_unlock_irqrestore(&host->lock, flags); return; }
static int sdhci_tegra_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct sdhci_tegra_soc_data *soc_data; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_tegra *tegra_host; struct clk *clk; int rc; match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); if (!match) return -EINVAL; soc_data = match->data; host = sdhci_pltfm_init(pdev, soc_data->pdata); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL); if (!tegra_host) { dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n"); rc = -ENOMEM; goto err_alloc_tegra_host; } tegra_host->soc_data = soc_data; pltfm_host->priv = tegra_host; sdhci_tegra_parse_dt(&pdev->dev, tegra_host); if (gpio_is_valid(tegra_host->power_gpio)) { rc = gpio_request(tegra_host->power_gpio, "sdhci_power"); if (rc) { dev_err(mmc_dev(host->mmc), "failed to allocate power gpio\n"); goto err_power_req; } gpio_direction_output(tegra_host->power_gpio, 1); } if (gpio_is_valid(tegra_host->cd_gpio)) { rc = gpio_request(tegra_host->cd_gpio, "sdhci_cd"); if (rc) { dev_err(mmc_dev(host->mmc), "failed to allocate cd gpio\n"); goto err_cd_req; } gpio_direction_input(tegra_host->cd_gpio); rc = request_irq(gpio_to_irq(tegra_host->cd_gpio), carddetect_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(host->mmc), host); if (rc) { dev_err(mmc_dev(host->mmc), "request irq error\n"); goto err_cd_irq_req; } } if (gpio_is_valid(tegra_host->wp_gpio)) { rc = gpio_request(tegra_host->wp_gpio, "sdhci_wp"); if (rc) { dev_err(mmc_dev(host->mmc), "failed to allocate wp gpio\n"); goto err_wp_req; } gpio_direction_input(tegra_host->wp_gpio); } clk = clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { dev_err(mmc_dev(host->mmc), "clk err\n"); rc = PTR_ERR(clk); goto err_clk_get; } clk_prepare_enable(clk); pltfm_host->clk = clk; if (tegra_host->is_8bit) host->mmc->caps |= MMC_CAP_8_BIT_DATA; rc = sdhci_add_host(host); if (rc) goto err_add_host; return 0; err_add_host: clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); err_clk_get: if (gpio_is_valid(tegra_host->wp_gpio)) gpio_free(tegra_host->wp_gpio); err_wp_req: if (gpio_is_valid(tegra_host->cd_gpio)) free_irq(gpio_to_irq(tegra_host->cd_gpio), host); err_cd_irq_req: if (gpio_is_valid(tegra_host->cd_gpio)) gpio_free(tegra_host->cd_gpio); err_cd_req: if (gpio_is_valid(tegra_host->power_gpio)) gpio_free(tegra_host->power_gpio); err_power_req: err_alloc_tegra_host: sdhci_pltfm_free(pdev); return rc; }
/* Routine to configure clock values. Exposed API to core */ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmc_omap_host *host = mmc_priv(mmc); u16 dsor = 0; unsigned long regval; unsigned long timeout; del_timer_sync(&host->inact_timer); omap_hsmmc_enable_clks(host); switch (ios->power_mode) { case MMC_POWER_OFF: mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); /* * Reset interface voltage to 3V if it's 1.8V now; * only relevant on MMC-1, the others always use 1.8V. * * REVISIT: If we are able to detect cards after unplugging * a 1.8V card, this code should not be needed. */ if (host->id != OMAP_MMC1_DEVID) break; if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { int vdd = fls(host->mmc->ocr_avail) - 1; if (omap_mmc_switch_opcond(host, vdd) != 0) host->mmc->ios.vdd = vdd; } break; case MMC_POWER_UP: mmc_slot(host).set_power(host->dev, host->slot_id, 1, ios->vdd); break; } switch (mmc->ios.bus_width) { case MMC_BUS_WIDTH_4: OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT); break; case MMC_BUS_WIDTH_1: OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT); break; } if (host->id == OMAP_MMC1_DEVID) { /* Only MMC1 can interface at 3V without some flavor * of external transceiver; but they all handle 1.8V. */ if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && (ios->vdd == DUAL_VOLT_OCR_BIT)) { /* * The mmc_select_voltage fn of the core does * not seem to set the power_mode to * MMC_POWER_UP upon recalculating the voltage. * vdd 1.8v. */ if (omap_mmc_switch_opcond(host, ios->vdd) != 0) dev_dbg(mmc_dev(host->mmc), "Switch operation failed\n"); } } if (ios->clock) { dsor = OMAP_MMC_MASTER_CLOCK / ios->clock; if (dsor < 1) dsor = 1; if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock) dsor++; if (dsor > 250) dsor = 250; } omap_mmc_stop_clock(host); regval = OMAP_HSMMC_READ(host->base, SYSCTL); regval = regval & ~(CLKD_MASK); regval = regval | (dsor << 6) | (DTO << 16); OMAP_HSMMC_WRITE(host->base, SYSCTL, regval); OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); /* Wait till the ICS bit is set */ timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != 0x2 && time_before(jiffies, timeout)) msleep(1); OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) | CEN); if (ios->power_mode == MMC_POWER_ON) send_init_stream(host); if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_READ(host->base, CON) | OD); omap_hsmmc_disable_clks(host); }