/* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) { if (!mmc_try_claim_host(host->mmc)) return 0; if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state && mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) { mmc_release_host(host->mmc); return 0; } mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); host->vdd = 0; host->power_mode = MMC_POWER_OFF; dev_dbg(mmc_dev(host->mmc), "%s -> OFF\n", host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); host->dpm_state = OFF; mmc_release_host(host->mmc); return 0; }
static int omap_hsmmc_remove(struct platform_device *pdev) { struct omap_hsmmc_host *host = platform_get_drvdata(pdev); struct resource *res; if (host) { mmc_host_enable(host->mmc); mmc_remove_host(host->mmc); if (host->pdata->cleanup) host->pdata->cleanup(&pdev->dev); free_irq(host->irq, host); if (mmc_slot(host).card_detect_irq) free_irq(mmc_slot(host).card_detect_irq, host); flush_scheduled_work(); mmc_host_disable(host->mmc); clk_disable(host->iclk); clk_put(host->fclk); clk_put(host->iclk); if (host->got_dbclk) { clk_disable(host->dbclk); clk_put(host->dbclk); } mmc_free_host(host->mmc); iounmap(host->base); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) release_mem_region(res->start, res->end - res->start + 1); platform_set_drvdata(pdev, NULL); return 0; }
static int omap_mmc_remove(struct platform_device *pdev) { struct mmc_omap_host *host = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); if (host) { host->pdata->cleanup(&pdev->dev); free_irq(host->irq, host); if (mmc_slot(host).card_detect_irq) free_irq(mmc_slot(host).card_detect_irq, host); flush_scheduled_work(); clk_disable(host->fclk); clk_disable(host->iclk); clk_put(host->fclk); clk_put(host->iclk); if (host->dbclk_enabled) { clk_disable(host->dbclk); clk_put(host->dbclk); } mmc_free_host(host->mmc); } return 0; }
static int omap_hsmmc_get_ro(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); if (!mmc_slot(host).get_ro) return -ENOSYS; return mmc_slot(host).get_ro(host->dev, 0); }
static int omap_hsmmc_get_cd(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); if (!mmc_slot(host).card_detect) return -ENOSYS; return mmc_slot(host).card_detect(mmc_slot(host).card_detect_irq); }
/* * Switch MMC interface voltage ... only relevant for MMC1. * * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver. * The MMC2 transceiver controls are used instead of DAT4..DAT7. * Some chips, like eMMC ones, use internal transceivers. */ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) { u32 reg_val = 0; int ret; /* Disable the clocks */ clk_disable(host->fclk); clk_disable(host->iclk); if (host->got_dbclk) clk_disable(host->dbclk); /* Turn the power off */ ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd); clk_enable(host->iclk); clk_enable(host->fclk); if (host->got_dbclk) clk_enable(host->dbclk); if (ret != 0) goto err; OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); reg_val = OMAP_HSMMC_READ(host->base, HCTL); /* * If a MMC dual voltage card is detected, the set_ios fn calls * this fn with VDD bit set for 1.8V. Upon card removal from the * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF. * * Cope with a bit of slop in the range ... per data sheets: * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max, * but recommended values are 1.71V to 1.89V * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max, * but recommended values are 2.7V to 3.3V * * Board setup code shouldn't permit anything very out-of-range. * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the * middle range) but VSIM can't power DAT4..DAT7 at more than 3V. */ if ((1 << vdd) <= MMC_VDD_23_24) reg_val |= SDVS18; else reg_val |= SDVS30; OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); set_sd_bus_power(host); return 0; err: dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); return ret; }
static inline int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host) { int r = 1; if (mmc_slot(host).get_cover_state) r = mmc_slot(host).get_cover_state(host->dev, host->slot_id); return r; }
static int omap_mmc_remove(struct platform_device *pdev) { struct mmc_omap_host *host = platform_get_drvdata(pdev); struct resource *res; u16 vdd = 0; /* * TODO: * The timer could kick in and turn off the clocks. * if mmc_remove_host touches the mmc module regs, this can * crash. So need to verify if mmc_remove_host indeed touches * the module regs. */ mmc_clk_try_enable(host); if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { /* * Set the vdd back to 3V, * applicable for dual volt support. */ vdd = fls(host->mmc->ocr_avail) - 1; if (omap_mmc_switch_opcond(host, vdd) != 0) host->mmc->ios.vdd = vdd; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) release_mem_region(res->start, res->end - res->start + 1); platform_set_drvdata(pdev, NULL); if (host) { mmc_remove_host(host->mmc); if (host->pdata->cleanup) host->pdata->cleanup(&pdev->dev); free_irq(host->irq, host); if (mmc_slot(host).card_detect_irq) free_irq(mmc_slot(host).card_detect_irq, host); flush_scheduled_work(); mmc_clk_try_disable(host); clk_put(host->fclk); clk_put(host->iclk); if (host->dbclk_enabled) { clk_disable(host->dbclk); clk_put(host->dbclk); } mmc_free_host(host->mmc); iounmap(host->base); } return 0; }
/* * Switch MMC operating voltage */ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) { u32 reg_val = 0; int ret; /* Disable the clocks */ clk_disable(host->fclk); clk_disable(host->iclk); clk_disable(host->dbclk); /* Turn the power off */ ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); if (ret != 0) goto err; /* Turn the power ON with given VDD 1.8 or 3.0v */ ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd); if (ret != 0) goto err; clk_enable(host->fclk); clk_enable(host->iclk); clk_enable(host->dbclk); OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); reg_val = OMAP_HSMMC_READ(host->base, HCTL); /* * If a MMC dual voltage card is detected, the set_ios fn calls * this fn with VDD bit set for 1.8V. Upon card removal from the * slot, mmc_omap_detect fn sets the VDD back to 3V. * * Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is * set in HCTL. */ if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) || ((1 << vdd) == MMC_VDD_33_34))) reg_val |= SDVS30; if ((1 << vdd) == MMC_VDD_165_195) reg_val |= SDVS18; OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) | SDBP); return 0; err: dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); return ret; }
/* * Work Item to notify the core about card insertion/removal */ static void omap_hsmmc_detect(struct work_struct *work) { struct omap_hsmmc_host *host = container_of(work, struct omap_hsmmc_host, mmc_carddetect_work); struct omap_mmc_slot_data *slot = &mmc_slot(host); int carddetect; if (host->suspended) return; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); if (slot->card_detect) carddetect = slot->card_detect(slot->card_detect_irq); else { omap_hsmmc_protect_card(host); carddetect = -ENOSYS; } if (carddetect) { mmc_detect_change(host->mmc, (HZ * 200) / 1000); } else { mmc_host_enable(host->mmc); omap_hsmmc_reset_controller_fsm(host, SRD); mmc_host_lazy_disable(host->mmc); mmc_detect_change(host->mmc, (HZ * 50) / 1000); } }
/* * ISR for handling card insertion and removal */ static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id) { struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id; host->carddetect = mmc_slot(host).card_detect(irq); schedule_work(&host->mmc_carddetect_work); return IRQ_HANDLED; }
static ssize_t omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr, char *buf) { struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); struct omap_hsmmc_host *host = mmc_priv(mmc); return sprintf(buf, "%s\n", mmc_slot(host).name); }
/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */ static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host) { int err, new_state; if (!mmc_try_claim_host(host->mmc)) return 0; clk_enable(host->fclk); omap_hsmmc_context_restore(host); if (mmc_card_can_sleep(host->mmc)) { err = mmc_card_sleep(host->mmc); if (err < 0) { clk_disable(host->fclk); mmc_release_host(host->mmc); return err; } new_state = CARDSLEEP; } else { new_state = REGSLEEP; } if (mmc_slot(host).set_sleep) mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0, new_state == CARDSLEEP); /* FIXME: turn off bus power and perhaps interrupts too */ clk_disable(host->fclk); host->dpm_state = new_state; mmc_release_host(host->mmc); dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n", host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || mmc_slot(host).card_detect || (mmc_slot(host).get_cover_state && mmc_slot(host).get_cover_state(host->dev, host->slot_id))) return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT); return 0; }
/* Handler for [SLEEP -> ENABLED] transition */ static int omap_hsmmc_sleep_to_enabled(struct omap_hsmmc_host *host) { if (!mmc_try_claim_host(host->mmc)) return 0; clk_enable(host->fclk); omap_hsmmc_context_restore(host); if (mmc_slot(host).set_sleep) mmc_slot(host).set_sleep(host->dev, host->slot_id, 0, host->vdd, host->dpm_state == CARDSLEEP); if (mmc_card_can_sleep(host->mmc)) mmc_card_awake(host->mmc); dev_dbg(mmc_dev(host->mmc), "%s -> ENABLED\n", host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); host->dpm_state = ENABLED; mmc_release_host(host->mmc); return 0; }
/* Protect the card while the cover is open */ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) { if (!mmc_slot(host).get_cover_state) return; host->reqs_blocked = 0; if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { if (host->protect_card) { printk(KERN_INFO "%s: cover is closed, " "card is now accessible\n", mmc_hostname(host->mmc)); host->protect_card = 0; } } else { if (!host->protect_card) { printk(KERN_INFO "%s: cover is open, " "card is now inaccessible\n", mmc_hostname(host->mmc)); host->protect_card = 1; } } }
static void omap_hsmmc_status_notify_cb(int card_present, void *dev_id) { struct mmc_omap_host *host = dev_id; struct omap_mmc_slot_data *slot = &mmc_slot(host); printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), card_present); host->carddetect = slot->card_detect(slot->card_detect_irq); sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); if (host->carddetect) { mmc_detect_change(host->mmc, (HZ * 200) / 1000); } else { mmc_omap_reset_controller_fsm(host, SRD); mmc_detect_change(host->mmc, (HZ * 50) / 1000); } }
/* * Work Item to notify the core about card insertion/removal */ static void mmc_omap_detect(struct work_struct *work) { struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, mmc_carddetect_work); struct omap_mmc_slot_data *slot = &mmc_slot(host); if (host->suspended) return; omap_hsmmc_enable_clks(host); host->carddetect = slot->card_detect(slot->card_detect_irq); sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); if (host->carddetect) { mmc_detect_change(host->mmc, (HZ * 200) / 1000); } else { mmc_detect_change(host->mmc, (HZ * 50) / 1000); } }
/* Routine to configure clock values. Exposed API to core */ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct omap_hsmmc_host *host = mmc_priv(mmc); u16 dsor = 0; unsigned long regval; unsigned long timeout; u32 con; int do_send_init_stream = 0; mmc_host_enable(host->mmc); if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF: mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); host->vdd = 0; break; case MMC_POWER_UP: mmc_slot(host).set_power(host->dev, host->slot_id, 1, ios->vdd); host->vdd = ios->vdd; break; case MMC_POWER_ON: do_send_init_stream = 1; break; } host->power_mode = ios->power_mode; } /* FIXME: set registers based only on changes to ios */ con = OMAP_HSMMC_READ(host->base, CON); switch (mmc->ios.bus_width) { case MMC_BUS_WIDTH_8: OMAP_HSMMC_WRITE(host->base, CON, con | DW8); break; case MMC_BUS_WIDTH_4: OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8); 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, CON, con & ~DW8); 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_hsmmc_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_hsmmc_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) != ICS && time_before(jiffies, timeout)) msleep(1); OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) | CEN); if (do_send_init_stream) send_init_stream(host); con = OMAP_HSMMC_READ(host->base, CON); if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) OMAP_HSMMC_WRITE(host->base, CON, con | OD); else OMAP_HSMMC_WRITE(host->base, CON, con & ~OD); if (host->power_mode == MMC_POWER_OFF) mmc_host_disable(host->mmc); else mmc_host_lazy_disable(host->mmc); }
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->use_dma = 1; 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); mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; mmc->f_max = 52000000; sema_init(&host->sem, 1); host->iclk = clk_get(&pdev->dev, "mmchs_ick"); if (IS_ERR(host->iclk)) { ret = PTR_ERR(host->iclk); host->iclk = NULL; goto err; } 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 err; } if (clk_enable(host->fclk) != 0) goto err; if (clk_enable(host->iclk) != 0) { clk_disable(host->fclk); clk_put(host->fclk); goto err; } host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); /* * MMC can still work without debounce clock. */ if (IS_ERR(host->dbclk)) dev_dbg(mmc_dev(host->mmc), "Failed to get debounce clock\n"); else if (clk_enable(host->dbclk) != 0) dev_dbg(mmc_dev(host->mmc), "Enabling debounce" " clk failed\n"); else host->dbclk_enabled = 1; mmc->ocr_avail = mmc_slot(host).ocr_mask; mmc->caps |= MMC_CAP_MULTIWRITE | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; if (pdata->conf.wire4) 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, pdev->name, host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); goto irq_err; } /* 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_DISABLED, "MMC CD", host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab MMC CD IRQ"); free_irq(host->irq, host); goto irq_err; } } INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect); if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { free_irq(mmc_slot(host).card_detect_irq, host); free_irq(host->irq, host); goto irq_err; } } OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); platform_set_drvdata(pdev, host); mmc_add_host(mmc); return 0; err: dev_dbg(mmc_dev(host->mmc), "Probe Failed\n"); if (host) mmc_free_host(mmc); return ret; irq_err: dev_dbg(mmc_dev(host->mmc), "Unable to configure MMC IRQs\n"); clk_disable(host->fclk); clk_disable(host->iclk); clk_put(host->fclk); clk_put(host->iclk); if (host->dbclk_enabled) { clk_disable(host->dbclk); clk_put(host->dbclk); } if (host) mmc_free_host(mmc); return ret; }
/* 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; switch (ios->power_mode) { case MMC_POWER_OFF: mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); 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 operate at 3V/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); }
static int omap_mmc_get_cd(struct mmc_host *mmc) { struct mmc_omap_host *host = mmc_priv(mmc); host->carddetect = mmc_slot(host).card_detect(0); return host->carddetect; }
static int __init omap_hsmmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; int ret = 0, irq; 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 omap_hsmmc_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->power_mode = -1; platform_set_drvdata(pdev, host); INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); if (mmc_slot(host).power_saving) mmc->ops = &omap_hsmmc_ps_ops; else mmc->ops = &omap_hsmmc_ops; mmc->f_min = 400000; mmc->f_max = 52000000; sema_init(&host->sem, 1); spin_lock_init(&host->irq_lock); host->iclk = clk_get(&pdev->dev, "ick"); if (IS_ERR(host->iclk)) { ret = PTR_ERR(host->iclk); host->iclk = NULL; goto err1; } host->fclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); host->fclk = NULL; clk_put(host->iclk); goto err1; } omap_hsmmc_context_save(host); mmc->caps |= MMC_CAP_DISABLE; mmc_set_disable_delay(mmc, OMAP_MMC_DISABLED_TIMEOUT); /* we start off in DISABLED state */ host->dpm_state = DISABLED; if (mmc_host_enable(host->mmc) != 0) { clk_put(host->iclk); clk_put(host->fclk); goto err1; } if (clk_enable(host->iclk) != 0) { mmc_host_disable(host->mmc); clk_put(host->iclk); clk_put(host->fclk); goto err1; } if (cpu_is_omap2430()) { host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); /* * MMC can still work without debounce clock. */ if (IS_ERR(host->dbclk)) dev_warn(mmc_dev(host->mmc), "Failed to get debounce clock\n"); else host->got_dbclk = 1; if (host->got_dbclk) if (clk_enable(host->dbclk) != 0) dev_dbg(mmc_dev(host->mmc), "Enabling debounce" " clk failed\n"); } /* Since we do only SG emulation, we can have as many segs * as we want. */ mmc->max_phys_segs = 1024; mmc->max_hw_segs = 1024; 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 | MMC_CAP_WAIT_WHILE_BUSY; if (mmc_slot(host).wires >= 8) mmc->caps |= MMC_CAP_8_BIT_DATA; else if (mmc_slot(host).wires >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; if (mmc_slot(host).nonremovable) mmc->caps |= MMC_CAP_NONREMOVABLE; omap_hsmmc_conf_bus_power(host); /* Select DMA lines */ switch (host->id) { case OMAP_MMC1_DEVID: host->dma_line_tx = OMAP24XX_DMA_MMC1_TX; host->dma_line_rx = OMAP24XX_DMA_MMC1_RX; break; case OMAP_MMC2_DEVID: host->dma_line_tx = OMAP24XX_DMA_MMC2_TX; host->dma_line_rx = OMAP24XX_DMA_MMC2_RX; break; case OMAP_MMC3_DEVID: host->dma_line_tx = OMAP34XX_DMA_MMC3_TX; host->dma_line_rx = OMAP34XX_DMA_MMC3_RX; break; case OMAP_MMC4_DEVID: host->dma_line_tx = OMAP44XX_DMA_MMC4_TX; host->dma_line_rx = OMAP44XX_DMA_MMC4_RX; break; case OMAP_MMC5_DEVID: host->dma_line_tx = OMAP44XX_DMA_MMC5_TX; host->dma_line_rx = OMAP44XX_DMA_MMC5_RX; break; default: dev_err(mmc_dev(host->mmc), "Invalid MMC id\n"); goto err_irq; } /* Request IRQ for MMC operations */ ret = request_irq(host->irq, omap_hsmmc_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), "Unable to configure MMC IRQs\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)) { ret = request_irq(mmc_slot(host).card_detect_irq, omap_hsmmc_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; } } OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); mmc_host_lazy_disable(host->mmc); omap_hsmmc_protect_card(host); mmc_add_host(mmc); if (mmc_slot(host).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).get_cover_state) { ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch); if (ret < 0) goto err_cover_switch; } omap_hsmmc_debugfs(mmc); 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: mmc_host_disable(host->mmc); clk_disable(host->iclk); clk_put(host->fclk); clk_put(host->iclk); if (host->got_dbclk) { clk_disable(host->dbclk); 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 __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); mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; mmc->f_max = 52000000; sema_init(&host->sem, 1); spin_lock_init(&host->clk_lock); spin_lock_init(&host->inits_lock); init_timer(&host->inact_timer); host->inact_timer.function = mmc_omap_inact_timer; host->inact_timer.data = (unsigned long) host; 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 (mmc_clk_try_enable(host) != 0) { clk_put(host->iclk); clk_put(host->fclk); goto err1; } if (cpu_is_omap2430()) { host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); /* * MMC can still work without debounce clock. */ if (IS_ERR(host->dbclk)) dev_dbg(mmc_dev(host->mmc), "Failed to get debounce clock\n"); else if (clk_enable(host->dbclk) != 0) dev_dbg(mmc_dev(host->mmc), "Enabling debounce" " clk failed\n"); else host->dbclk_enabled = 1; } #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->ocr_avail = mmc_slot(host).ocr_mask; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; if (pdata->slots[host->slot_id].wire8) { if (is_sil_rev_equal_to(OMAP3430_REV_ES3_0)) mmc->caps |= MMC_CAP_8_BIT_DATA; else mmc->caps |= MMC_CAP_4_BIT_DATA; } if (pdata->slots[host->slot_id].wire4) mmc->caps |= MMC_CAP_4_BIT_DATA; hctl = SDVS30; capa = VS30 | 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 to SIDLE & Auto Idle mode */ OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SIDLE_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; } /* 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; } } else if (mmc_slot(host).card_detect) { mmc->caps |= MMC_CAP_NEEDS_POLL; } INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect); if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { dev_dbg(mmc_dev(host->mmc), "Unable to configure MMC IRQs\n"); goto err_irq_cd_init; } } OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); platform_set_drvdata(pdev, host); 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_init: free_irq(mmc_slot(host).card_detect_irq, host); err_irq_cd: free_irq(host->irq, host); err_irq: mmc_clk_try_disable(host); clk_put(host->fclk); clk_put(host->iclk); if (host->dbclk_enabled) { clk_disable(host->dbclk); 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; }
/* 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; u32 con; 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_8: OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_READ(host->base, CON) | DW8); break; case MMC_BUS_WIDTH_4: OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_READ(host->base, CON) & ~DW8); 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, CON, OMAP_HSMMC_READ(host->base, CON) & ~DW8); 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); con = OMAP_HSMMC_READ(host->base, CON); if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) OMAP_HSMMC_WRITE(host->base, CON, con | OD); else OMAP_HSMMC_WRITE(host->base, CON, con & ~OD); omap_hsmmc_disable_clks(host); }
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; }