/* * drivers/mmc/host/omap_hsmmc.c * * Driver for OMAP2430/3430 MMC controller. * * Copyright (C) 2007 Texas Instruments. * * Authors: * Syed Mohammed Khasim <x0khasim@ti.com> * Madhusudhan <madhu.cr@ti.com> * Mohit Jalori <mjalori@ti.com> * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied.
*/
/* * One controller can have multiple slots, like on some omap boards using * omap.c controller driver. Luckily this is not currently done on any known * omap_hsmmc.c device.
*/ #define mmc_pdata(host) host->pdata
if (!IS_ERR(mmc->supply.vmmc)) {
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); if (ret) return ret;
}
/* Enable interface voltage rail, if needed */ if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
ret = regulator_enable(mmc->supply.vqmmc); if (ret) {
dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n"); goto err_vqmmc;
}
host->vqmmc_enabled = true;
}
return 0;
err_vqmmc: if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
return ret;
}
staticint omap_hsmmc_disable_supply(struct mmc_host *mmc)
{ int ret; int status; struct omap_hsmmc_host *host = mmc_priv(mmc);
if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
ret = regulator_disable(mmc->supply.vqmmc); if (ret) {
dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n"); return ret;
}
host->vqmmc_enabled = false;
}
if (!IS_ERR(mmc->supply.vmmc)) {
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); if (ret) goto err_set_ocr;
}
return 0;
err_set_ocr: if (!IS_ERR(mmc->supply.vqmmc)) {
status = regulator_enable(mmc->supply.vqmmc); if (status)
dev_err(mmc_dev(mmc), "vmmc_aux re-enable failed\n");
}
return ret;
}
staticint omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on)
{ int ret;
if (IS_ERR(host->pbias)) return 0;
if (power_on) { if (!host->pbias_enabled) {
ret = regulator_enable(host->pbias); if (ret) {
dev_err(host->dev, "pbias reg enable fail\n"); return ret;
}
host->pbias_enabled = true;
}
} else { if (host->pbias_enabled) {
ret = regulator_disable(host->pbias); if (ret) {
dev_err(host->dev, "pbias reg disable fail\n"); return ret;
}
host->pbias_enabled = false;
}
}
return 0;
}
staticint omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on)
{ struct mmc_host *mmc = host->mmc; int ret = 0;
/* * If we don't see a Vcc regulator, assume it's a fixed * voltage always-on regulator.
*/ if (IS_ERR(mmc->supply.vmmc)) return 0;
ret = omap_hsmmc_set_pbias(host, false); if (ret) return ret;
/* * Assume Vcc regulator is used only to power the card ... OMAP * VDDS is used to power the pins, optionally with a transceiver to * support cards using voltages other than VDDS (1.8V nominal). When a * transceiver is used, DAT3..7 are muxed as transceiver control pins. * * In some cases this regulator won't support enable/disable; * e.g. it's a fixed rail for a WLAN chip. * * In other cases vcc_aux switches interface power. Example, for * eMMC cards it represents VccQ. Sometimes transceivers or SDIO * chips/cards need an interface voltage rail too.
*/ if (power_on) {
ret = omap_hsmmc_enable_supply(mmc); if (ret) return ret;
ret = omap_hsmmc_set_pbias(host, true); if (ret) goto err_set_voltage;
} else {
ret = omap_hsmmc_disable_supply(mmc); if (ret) return ret;
}
return 0;
err_set_voltage:
omap_hsmmc_disable_supply(mmc);
return ret;
}
staticint omap_hsmmc_disable_boot_regulator(struct regulator *reg)
{ int ret;
if (IS_ERR(reg)) return 0;
if (regulator_is_enabled(reg)) {
ret = regulator_enable(reg); if (ret) return ret;
ret = regulator_disable(reg); if (ret) return ret;
}
/* * disable regulators enabled during boot and get the usecount * right so that regulators can be enabled/disabled by checking * the return value of regulator_is_enabled
*/
ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vmmc); if (ret) {
dev_err(host->dev, "fail to disable boot enabled vmmc reg\n"); return ret;
}
ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vqmmc); if (ret) {
dev_err(host->dev, "fail to disable boot enabled vmmc_aux reg\n"); return ret;
}
ret = omap_hsmmc_disable_boot_regulator(host->pbias); if (ret) {
dev_err(host->dev, "failed to disable boot enabled pbias reg\n"); return ret;
}
ret = mmc_regulator_get_supply(mmc); if (ret) return ret;
/* Allow an aux regulator */ if (IS_ERR(mmc->supply.vqmmc)) {
mmc->supply.vqmmc = devm_regulator_get_optional(host->dev, "vmmc_aux"); if (IS_ERR(mmc->supply.vqmmc)) {
ret = PTR_ERR(mmc->supply.vqmmc); if ((ret != -ENODEV) && host->dev->of_node) return ret;
dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n",
PTR_ERR(mmc->supply.vqmmc));
}
}
host->pbias = devm_regulator_get_optional(host->dev, "pbias"); if (IS_ERR(host->pbias)) {
ret = PTR_ERR(host->pbias); if ((ret != -ENODEV) && host->dev->of_node) {
dev_err(host->dev, "SD card detect fail? enable CONFIG_REGULATOR_PBIAS\n"); return ret;
}
dev_dbg(host->dev, "unable to get pbias regulator %ld\n",
PTR_ERR(host->pbias));
}
/* For eMMC do not power off when not in sleep state */ if (mmc_pdata(host)->no_regulator_off_init) return 0;
ret = omap_hsmmc_disable_boot_regulators(host); if (ret) return ret;
return 0;
}
/* * Start clock to the card
*/ staticvoid omap_hsmmc_start_clock(struct omap_hsmmc_host *host)
{
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
}
/* * Stop clock to the card
*/ staticvoid omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
{
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN); if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stopped\n");
}
spin_lock_irqsave(&host->irq_lock, flags); /* no transfer running but need to keep cirq if enabled */ if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
irq_mask |= CIRQ_EN;
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
spin_unlock_irqrestore(&host->irq_lock, flags);
}
/* Calculate divisor for the given clock frequency */ static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
{
u16 dsor = 0;
if (ios->clock) {
dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock); if (dsor > CLKD_MAX)
dsor = CLKD_MAX;
}
/* 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))
cpu_relax();
/* * Enable High-Speed Support * Pre-Requisites * - Controller should support High-Speed-Enable Bit * - Controller should not be using DDR Mode * - Controller should advertise that it supports High Speed * in capabilities register * - MMC/SD clock coming out of controller > 25MHz
*/ if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) &&
(ios->timing != MMC_TIMING_MMC_DDR52) &&
(ios->timing != MMC_TIMING_UHS_DDR50) &&
((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
regval = OMAP_HSMMC_READ(host->base, HCTL); if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
regval |= HSPE; else
regval &= ~HSPE;
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);
}
#ifdef CONFIG_PM
/* * Restore the MMC host context, if it was lost as result of a * power state change.
*/ staticint omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
{ struct mmc_ios *ios = &host->mmc->ios;
u32 hctl, capa; unsignedlong timeout;
/* * Save the MMC host context (store the number of power state changes so far).
*/ staticvoid omap_hsmmc_context_save(struct omap_hsmmc_host *host)
{
host->con = OMAP_HSMMC_READ(host->base, CON);
host->hctl = OMAP_HSMMC_READ(host->base, HCTL);
host->sysctl = OMAP_HSMMC_READ(host->base, SYSCTL);
host->capa = OMAP_HSMMC_READ(host->base, CAPA);
}
/* * Unlike OMAP1 controller, the cmdtype does not seem to be based on * ac, bc, adtc, bcr. Only commands ending an open ended transfer need * a val of 0x3, rest 0x0.
*/ if (cmd == host->mrq->stop)
cmdtype = 0x3;
omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ if (mrq->data && host->use_dma && dma_ch != -1) return;
host->mrq = NULL;
mmc_request_done(host->mmc, mrq);
}
/* * Notify the transfer complete to MMC core
*/ staticvoid
omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
{ if (!data) { struct mmc_request *mrq = host->mrq;
/* TC before CC from CMD6 - don't know why, but it happens */ if (host->cmd && host->cmd->opcode == 6 &&
host->response_busy) {
host->response_busy = 0; return;
}
/* * MMC controller internal state machines reset * * Used to reset command or data internal state machines, using respectively * SRC or SRD bit of SYSCTL register * Can be called from interrupt context
*/ staticinlinevoid omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, unsignedlong bit)
{ unsignedlong i = 0; unsignedlong limit = MMC_TIMEOUT_US;
/* * OMAP4 ES2 and greater has an updated reset logic. * Monitor a 0->1 transition first
*/ if (mmc_pdata(host)->features & HSMMC_HAS_UPDATED_RESET) { while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit))
udelay(1);
}
i = 0;
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
(i++ < limit))
udelay(1);
if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
dev_err(mmc_dev(host->mmc), "Timeout waiting on controller reset in %s\n",
__func__);
}
staticvoid hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err, int end_cmd)
{ if (end_cmd) {
omap_hsmmc_reset_controller_fsm(host, SRC); if (host->cmd)
host->cmd->error = err;
}
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) | SDBP); for (i = 0; i < loops_per_jiffy; i++) { if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP) break;
cpu_relax();
}
}
/* * 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.
*/ staticint omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
{
u32 reg_val = 0; int ret;
/* Disable the clocks */
clk_disable_unprepare(host->dbclk);
/* Turn the power off */
ret = omap_hsmmc_set_power(host, 0);
/* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret)
ret = omap_hsmmc_set_power(host, 1);
clk_prepare_enable(host->dbclk);
/* * 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;
/* Sanity check: all the SG entries must be aligned by block size. */ for (i = 0; i < data->sg_len; i++) { struct scatterlist *sgl;
sgl = data->sg + i; if (sgl->length % data->blksz) return -EINVAL;
} if ((data->blksz % 4) != 0) /* REVISIT: The MMC buffer increments only when MSB is written. * Return error for blksz which is non multiple of four.
*/ return -EINVAL;
BUG_ON(host->dma_ch != -1);
chan = omap_hsmmc_get_dma_chan(host, data);
ret = dmaengine_slave_config(chan, &cfg); if (ret) return ret;
ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, chan); if (ret) return ret;
/* Routine to configure clock values. Exposed API to core */ staticvoid omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{ struct omap_hsmmc_host *host = mmc_priv(mmc); int do_send_init_stream = 0;
if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF:
omap_hsmmc_set_power(host, 0); break; case MMC_POWER_UP:
omap_hsmmc_set_power(host, 1); 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 */
omap_hsmmc_set_bus_width(host);
if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) { /* 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 enable, piggy back detection on current request * but always disable immediately
*/ if (!host->req_in_progress || !enable)
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
staticint omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host)
{ int ret;
/* * For omaps with wake-up path, wakeirq will be irq from pinctrl and * for other omaps, wakeirq will be from GPIO (dat line remuxed to * gpio). wakeirq is needed to detect sdio irq in runtime suspend state * with functional clock disabled.
*/ if (!host->dev->of_node || !host->wake_irq) return -ENODEV;
ret = dev_pm_set_dedicated_wake_irq(host->dev, host->wake_irq); if (ret) {
dev_err(mmc_dev(host->mmc), "Unable to request wake IRQ\n"); goto err;
}
/* * Some omaps don't have wake-up path from deeper idle states * and need to remux SDIO DAT1 to GPIO for wake-up from idle.
*/ if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) { struct pinctrl *p = devm_pinctrl_get(host->dev); if (IS_ERR(p)) {
ret = PTR_ERR(p); goto err_free_irq;
}
if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_IDLE))) {
dev_info(host->dev, "missing idle pinctrl state\n");
devm_pinctrl_put(p);
ret = -EINVAL; goto err_free_irq;
}
devm_pinctrl_put(p);
}
value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
value = OMAP_HSMMC_READ(host->base, CAPA);
OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
/* Set SD bus power bit */
set_sd_bus_power(host);
}
staticint omap_hsmmc_multi_io_quirk(struct mmc_card *card, unsignedint direction, int blk_size)
{ /* This controller can't do multiblock reads due to hw bugs */ if (direction == MMC_DATA_READ) return 1;
host->dbclk = devm_clk_get(&pdev->dev, "mmchsdb_fck"); /* * MMC can still work without debounce clock.
*/ if (IS_ERR(host->dbclk)) {
host->dbclk = NULL;
} elseif (clk_prepare_enable(host->dbclk) != 0) {
dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
host->dbclk = NULL;
}
/* Set this to a value that allows allocating an entire descriptor
* list within a page (zero order allocation). */
mmc->max_segs = 64;
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->caps |= mmc_pdata(host)->caps; if (mmc->caps & MMC_CAP_8_BIT_DATA)
mmc->caps |= MMC_CAP_4_BIT_DATA;
if (mmc_pdata(host)->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
mmc->pm_caps |= mmc_pdata(host)->pm_caps;
omap_hsmmc_conf_bus_power(host);
host->rx_chan = dma_request_chan(&pdev->dev, "rx"); if (IS_ERR(host->rx_chan)) {
dev_err(mmc_dev(host->mmc), "RX DMA channel request failed\n");
ret = PTR_ERR(host->rx_chan); goto err_irq;
}
host->tx_chan = dma_request_chan(&pdev->dev, "tx"); if (IS_ERR(host->tx_chan)) {
dev_err(mmc_dev(host->mmc), "TX DMA channel request failed\n");
ret = PTR_ERR(host->tx_chan); goto err_irq;
}
/* * Limit the maximum segment size to the lower of the request size * and the DMA engine device segment size limits. In reality, with * 32-bit transfers, the DMA engine can do longer segments than this * but there is no way to represent that in the DMA model - if we * increase this figure here, we get warnings from the DMA API debug.
*/
mmc->max_seg_size = min3(mmc->max_req_size,
dma_get_max_seg_size(host->rx_chan->device->dev),
dma_get_max_seg_size(host->tx_chan->device->dev));
/* Request IRQ for MMC operations */
ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0,
mmc_hostname(mmc), host); if (ret) {
dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); goto err_irq;
}
ret = omap_hsmmc_reg_get(host); if (ret) goto err_irq;
if (!mmc->ocr_avail)
mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
omap_hsmmc_disable_irq(host);
/* * For now, only support SDIO interrupt if we have a separate * wake-up interrupt configured from device tree. This is because * the wake-up interrupt is needed for idle state and some * platforms need special quirks. And we don't want to add new * legacy mux platform init code callbacks any longer as we * are moving to DT based booting anyways.
*/
ret = omap_hsmmc_configure_wake_irq(host); if (!ret)
mmc->caps |= MMC_CAP_SDIO_IRQ;
ret = mmc_add_host(mmc); if (ret) goto err_irq;
if (mmc_pdata(host)->name != NULL) {
ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name); if (ret < 0) goto err_slot_name;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.