static int __devinit sdhci_sprd_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct sdhci_host *host; struct resource *res; int ret, irq; #ifdef CONFIG_MMC_CARD_HOTPLUG int sd_detect_gpio; int detect_irq; #endif struct sprd_host_data *host_data; irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "no irq specified\n"); return irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "no memory specified\n"); return -ENOENT; } if(pdev->id == 0) { sd_buffer_pre_alloc(); } host = sdhci_alloc_host(dev, sizeof(struct sprd_host_data)); if (IS_ERR(host)) { dev_err(dev, "sdhci_alloc_host() failed\n"); return PTR_ERR(host); } host_data = sdhci_priv(host); host_data->platdata = dev_get_platdata(dev); host_data->clk_enable = 0; BUG_ON(NULL == host_data->platdata); printk("sdio probe %s, vdd %s (%d), clk %s parent %s\n", host_data->platdata->hw_name, host_data->platdata->vdd_name, host_data->platdata->volt_level, host_data->platdata->clk_name, host_data->platdata->clk_parent); platform_set_drvdata(pdev, host); host->vmmc = NULL; host->vmmc_ext = NULL; host->ioaddr = (void __iomem *)res->start; printk("sdio: host->ioaddr:0x%x\n", (u32)host->ioaddr); host->hw_name = (host_data->platdata->hw_name)? host_data->platdata->hw_name:pdev->name; host->ops = &sdhci_sprd_ops; host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |\ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |\ SDHCI_QUIRK_BROKEN_CARD_DETECTION|\ SDHCI_QUIRK_INVERTED_WRITE_PROTECT; host->irq = irq; #ifdef CONFIG_MMC_CARD_HOTPLUG sd_detect_gpio = host_data->platdata->detect_gpio; if(sd_detect_gpio > 0){ pr_info("%s, sd_detect_gpio:%d\n", __func__, sd_detect_gpio); if (0 == pdev->id){ ret = gpio_request(sd_detect_gpio, "sdio0_detect"); }else{ ret = gpio_request(sd_detect_gpio, "sdio1_detect"); } if (ret) { dev_err(dev, "cannot request gpio\n"); return -1; } ret = gpio_direction_input(sd_detect_gpio); if (ret) { dev_err(dev, "gpio can not change to input\n"); return -1; } detect_irq = gpio_to_irq(sd_detect_gpio); if (detect_irq < 0){ dev_err(dev, "cannot alloc detect irq\n"); return -1; } host_data->detect_irq = detect_irq; }else if (host_data->platdata->register_status_notify) { host_data->platdata->register_status_notify(sdhci_status_notify_cb, host); } else if (!host_data->platdata->status) { printk("%s: No card detect facilities available\n", mmc_hostname(host->mmc)); }else{ printk("%s, sd_detect_gpio == 0 \n", __func__ ); } #endif if(host_data->platdata->vdd_name) { host->vmmc = regulator_get(NULL, host_data->platdata->vdd_name); BUG_ON(IS_ERR(host->vmmc)); if(!is_sd_slot(host)) regulator_enable(host->vmmc); } if(host_data->platdata->vdd_ext_name) { host->vmmc_ext = regulator_get(NULL, host_data->platdata->vdd_ext_name); BUG_ON(IS_ERR(host->vmmc_ext)); regulator_enable(host->vmmc_ext); } host->clk = NULL; sdhci_module_init(host); switch(pdev->id) { case 0: host->mmc->pm_flags |= MMC_PM_ONLY_USED_SDIO0_SHARK; host->caps = sdhci_readl(host, SDHCI_CAPABILITIES) & (~(SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180)); host->quirks |= SDHCI_QUIRK_MISSING_CAPS; host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; break; case 1: host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY|MMC_PM_KEEP_POWER |MMC_PM_DISABLE_TIMEOUT_IRQ; host->mmc->pm_caps |= MMC_PM_KEEP_POWER |MMC_PM_DISABLE_TIMEOUT_IRQ; #ifdef CONFIG_SDIO_CARD host->mmc->caps |= MMC_CAP_4_BIT_DATA |MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD; #else host->mmc->caps |= MMC_CAP_4_BIT_DATA |MMC_CAP_NONREMOVABLE; #endif break; case 2: host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY | MMC_PM_KEEP_POWER; host->mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD; break; case 3: host->caps = sdhci_readl(host, SDHCI_CAPABILITIES) & (~(SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_300)); host->quirks |= SDHCI_QUIRK_MISSING_CAPS; host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY | MMC_PM_KEEP_POWER; host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA | MMC_CAP_HW_RESET; break; default: BUG(); break; } #ifdef CONFIG_PM_RUNTIME switch(pdev->id) { case 1: case 2: #ifdef CONFIG_SDIO_CARD pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_no_callbacks(mmc_classdev(host->mmc)); pm_suspend_ignore_children(mmc_classdev(host->mmc), true); pm_runtime_set_active(mmc_classdev(host->mmc)); pm_runtime_enable(mmc_classdev(host->mmc)); #endif break; case 3: case 0: pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); default: break; } #endif ret = sdhci_add_host(host); if (ret) { dev_err(dev, "sdhci_add_host() failed\n"); goto err_add_host; } #ifdef CONFIG_MMC_BUS_SCAN if (pdev->id == 1) sdhci_host_g = host; #endif return 0; err_add_host: #ifdef CONFIG_PM_RUNTIME pm_runtime_disable(&(pdev)->dev); pm_runtime_set_suspended(&(pdev)->dev); #endif if (host_data->clk_enable) { clk_disable(host->clk); host_data->clk_enable = 0; } sdhci_free_host(host); return ret; }
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; }