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; /* 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); irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!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->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 /* * Setup DMA */ msmsdcc_init_dma(host); /* * Setup main peripheral bus clock */ host->pclk = clk_get(&pdev->dev, "sdc_pclk"); if (IS_ERR(host->pclk)) { ret = PTR_ERR(host->pclk); printk(KERN_ERR "%s: failed to get pclock (%d)\n", __func__, ret); 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, "sdc_clk"); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); printk(KERN_ERR "%s: failed to get clock (%d)\n", __func__, ret); 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 (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(irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto stat_irq_free; ret = request_irq(irqres->end, 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) 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(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 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->card_always_on = (plat->power_gpio == -1) ? 1 : 0; host->wp_gpio = plat->wp_gpio; 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_RUNTIME_DISABLE; if (plat->force_hs != 0) sdhci->quirks |= SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE; #ifdef CONFIG_MMC_EMBEDDED_SDIO mmc_set_embedded_sdio_data(sdhci->mmc, &plat->cis, &plat->cccr, plat->funcs, plat->num_funcs); #endif if (host->card_always_on) sdhci->mmc->pm_flags |= 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->register_status_notify) { plat->register_status_notify( tegra_sdhci_status_notify_cb, sdhci); } 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; }
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 __init omap_mmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; struct mmc_omap_host *host = NULL; struct resource *res; int ret = 0, irq; u32 hctl, capa; if (pdata == NULL) { dev_err(&pdev->dev, "Platform Data is missing\n"); return -ENXIO; } if (pdata->nr_slots == 0) { dev_err(&pdev->dev, "No Slots\n"); return -ENXIO; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (res == NULL || irq < 0) return -ENXIO; res = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (res == NULL) return -EBUSY; mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; goto err; } host = mmc_priv(mmc); host->mmc = mmc; host->pdata = pdata; host->dev = &pdev->dev; host->use_dma = 1; host->dev->dma_mask = &pdata->dma_mask; host->dma_ch = -1; host->irq = irq; host->id = pdev->id; host->slot_id = 0; host->mapbase = res->start; host->base = ioremap(host->mapbase, SZ_4K); host->shutdown = 0; host->max_vdd1_opp = pdata->max_vdd1_opp; host->min_vdd1_opp = pdata->min_vdd1_opp; #ifdef CONFIG_HC_Broken_eMMC_ZOOM2 /* * HACK: * The HC eMMC card on Zoom2 is broken. It reports wrong ext_csd * version. This is a hack to make the eMMC card useble on Zoom2. * Without this hack the MMC core fails to detect the correct size * of the card and hence accesses beyond the detected boundary results * in DATA CRC errors. * Make use of the unused bit to indicate the host controller ID to * the MMC core. */ if (host->id == OMAP_MMC2_DEVID) host->mmc->unused = 1; #endif #ifdef CONFIG_MMC_EMBEDDED_SDIO if (pdata->slots[0].embedded_sdio) mmc_set_embedded_sdio_data(mmc, &pdata->slots[0].embedded_sdio->cis, &pdata->slots[0].embedded_sdio->cccr, pdata->slots[0].embedded_sdio->funcs, pdata->slots[0].embedded_sdio->num_funcs); #endif platform_set_drvdata(pdev, host); INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect); INIT_WORK(&host->mmc_opp_set_work, mmc_omap_opp_setup); mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; mmc->f_max = 52000000; sema_init(&host->sem, 1); spin_lock_init(&host->clk_lock); init_timer(&host->inact_timer); host->inact_timer.function = omap_hsmmc_inact_timer; host->inact_timer.data = (unsigned long) host; host->clks_enabled = 0; host->off_counter = 0; host->inactive = 0; host->card_sleep = 0; host->iclk = clk_get(&pdev->dev, "mmchs_ick"); if (IS_ERR(host->iclk)) { ret = PTR_ERR(host->iclk); host->iclk = NULL; goto err1; } host->fclk = clk_get(&pdev->dev, "mmchs_fck"); if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); host->fclk = NULL; clk_put(host->iclk); goto err1; } if (cpu_is_omap2430()) { host->dbclk_enabled = 0; host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); } if (omap_hsmmc_enable_clks(host) != 0) { clk_put(host->iclk); clk_put(host->fclk); goto err1; } #ifdef CONFIG_MMC_BLOCK_BOUNCE mmc->max_phys_segs = 1; mmc->max_hw_segs = 1; #endif mmc->max_blk_size = 512; /* Block Length at max can be 1024 */ mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; if (mmc_slot(host).wires >= 8) mmc->caps |= MMC_CAP_8_BIT_DATA; else if (pdata->slots[host->slot_id].wires >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; /* Only MMC1 supports 3.0V */ if (host->id == OMAP_MMC1_DEVID) { hctl = SDVS30; capa = VS30 | VS18; } else { hctl = SDVS18; capa = VS18; } OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) | hctl); OMAP_HSMMC_WRITE(host->base, CAPA, OMAP_HSMMC_READ(host->base, CAPA) | capa); /* Set the controller to AUTO IDLE mode */ OMAP_HSMMC_WRITE(host->base, SYSCONFIG, OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE); /* Set SD bus power bit */ OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) | SDBP); /* Request IRQ for MMC operations */ ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); goto err_irq; } /* initialize power supplies, gpios, etc */ if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { dev_dbg(mmc_dev(host->mmc), "late init error\n"); goto err_irq_cd_init; } } mmc->ocr_avail = mmc_slot(host).ocr_mask; /* Request IRQ for card detect */ if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) { ret = request_irq(mmc_slot(host).card_detect_irq, omap_mmc_cd_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab MMC CD IRQ\n"); goto err_irq_cd; } } #ifdef CONFIG_MMC_EMBEDDED_SDIO else if (mmc_slot(host).register_status_notify) { mmc_slot(host).register_status_notify(omap_hsmmc_status_notify_cb, host); } #endif OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); mmc_add_host(mmc); if (host->pdata->slots[host->slot_id].name != NULL) { ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name); if (ret < 0) goto err_slot_name; } if (mmc_slot(host).card_detect_irq && mmc_slot(host).card_detect && host->pdata->slots[host->slot_id].get_cover_state) { ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch); if (ret < 0) goto err_cover_switch; } return 0; err_cover_switch: device_remove_file(&mmc->class_dev, &dev_attr_cover_switch); err_slot_name: mmc_remove_host(mmc); err_irq_cd: free_irq(mmc_slot(host).card_detect_irq, host); err_irq_cd_init: free_irq(host->irq, host); err_irq: omap_hsmmc_disable_clks(host); clk_put(host->fclk); clk_put(host->iclk); if (cpu_is_omap2430()) clk_put(host->dbclk); err1: iounmap(host->base); err: dev_dbg(mmc_dev(host->mmc), "Probe Failed\n"); release_mem_region(res->start, res->end - res->start + 1); if (host) mmc_free_host(mmc); 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); /* default value for gpio polarity */ host->cd_gpio_polarity = 0; host->wp_gpio_polarity = 1; host->power_gpio_polarity = 1; host->sdhci = sdhci; host->card_always_on = (plat->power_gpio == -1) ? 1 : 0; host->pdev = pdev; host->gpio_pins = plat->gpio_pins; host->nr_gpio_pins = plat->nr_gpio_pins; host->wp_gpio = plat->wp_gpio; host->wp_gpio_polarity = plat->wp_gpio_polarity; host->cd_gpio = plat->cd_gpio; host->cd_gpio_polarity = plat->cd_gpio_polarity; host->power_gpio = plat->power_gpio; host->power_gpio_polarity = plat->power_gpio_polarity; host->card_detection_time = jiffies; dev_info(&pdev->dev, "write protect: %d card detect: %d, power gpio: %d \n", host->wp_gpio, host->cd_gpio, host->power_gpio); if (host->cd_gpio == -1) { host->card_present = host->card_present = true; } sdhc_pinmux_config_gpio(host); 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_BROKEN_CARD_DETECTION; if (host->cd_gpio != -1) { sdhci->quirks |= SDHCI_QUIRK_RUNTIME_DISABLE; } if (plat->force_hs != 0) sdhci->quirks |= SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE; #ifdef CONFIG_MMC_EMBEDDED_SDIO mmc_set_embedded_sdio_data(sdhci->mmc, &plat->cis, &plat->cccr, plat->funcs, plat->num_funcs); #endif if (host->card_always_on) sdhci->mmc->pm_flags |= 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 = gpio_request(host->cd_gpio, "card_detect"); if (rc < 0) { dev_err(&pdev->dev, "request cd gpio failed = %d \n", host->cd_gpio); host->cd_gpio = -1; goto err_remove_host; } host->irq_cd = gpio_to_irq(host->cd_gpio); if (host->irq_cd < 0) { dev_err(&pdev->dev, "invalid card detect GPIO\n"); host->cd_gpio = -1; host->irq_cd = -1; goto err_remove_host; } tegra_gpio_enable(host->cd_gpio); rc = gpio_direction_input(host->cd_gpio); if (rc < 0) { dev_err(&pdev->dev, "failed to configure GPIO\n"); gpio_free(host->cd_gpio); host->cd_gpio = -1; goto err_remove_host; } 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; host->card_present = host->card_present_old = (gpio_get_value(plat->cd_gpio) == host->cd_gpio_polarity); dev_info(&pdev->dev, "host->card_present = %d \n", host->card_present); } else if (plat->register_status_notify) { plat->register_status_notify( tegra_sdhci_status_notify_cb, sdhci); } if (plat->cd_gpio == -1) host->card_present = true; if (host->wp_gpio != -1) { rc = gpio_request(host->wp_gpio, "write_protect"); if (rc < 0) { dev_err(&pdev->dev, "request wp gpio failed = %d \n", host->wp_gpio); host->wp_gpio = -1; goto err_remove_host; } tegra_gpio_enable(host->wp_gpio); rc = gpio_direction_input(host->wp_gpio); if (rc < 0) { dev_err(&pdev->dev, "configure wp gpio failed\n"); gpio_free(host->wp_gpio); host->wp_gpio = -1; goto err_remove_host; } } if (host->power_gpio != -1) { rc = gpio_request(host->power_gpio, "power_gpio"); if (rc < 0) { dev_err(&pdev->dev, "request power gpio failed = %d \n", host->power_gpio); host->power_gpio = -1; goto err_remove_host; } tegra_gpio_enable(host->power_gpio); rc = gpio_direction_output(host->power_gpio, !host->power_gpio_polarity); if (rc < 0) { dev_err(&pdev->dev, "configure power gpio failed\n"); gpio_free(host->power_gpio); host->power_gpio = -1; goto err_remove_host; } if (host->card_present) { tasklet_schedule(&sdhci->card_tasklet); } } 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; }