// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/host/pxa.c - PXA MMCI driver * * Copyright (C) 2003 Russell King, All Rights Reserved. * * This hardware is really sick: * - No way to clear interrupts. * - Have to turn off the clock whenever we touch the device. * - Doesn't tell you how many data blocks were transferred. * Yuck! * * 1 and 3 byte data transfers not supported * max block length up to 1023
*/ #include <linux/module.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/mmc/host.h> #include <linux/mmc/slot-gpio.h> #include <linux/io.h> #include <linux/regulator/consumer.h> #include <linux/gpio/consumer.h> #include <linux/gfp.h> #include <linux/of.h> #include <linux/soc/pxa/cpu.h>
/* * workaround for erratum #91: * only start DMA now if we are doing a read, * otherwise we wait until CMD/RESP has finished * before starting DMA.
*/ if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
dma_async_issue_pending(chan);
}
/* * Did I mention this is Sick. We always need to * discard the upper 8 bits of the first 16-bit word.
*/
v = readl(host->base + MMC_RES) & 0xffff; for (i = 0; i < 4; i++) {
u32 w1 = readl(host->base + MMC_RES) & 0xffff;
u32 w2 = readl(host->base + MMC_RES) & 0xffff;
cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
v = w2;
}
if (stat & STAT_TIME_OUT_RESPONSE) {
cmd->error = -ETIMEDOUT;
} elseif (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { /* * workaround for erratum #42: * Intel PXA27x Family Processor Specification Update Rev 001 * A bogus CRC error can appear if the msb of a 136 bit * response is a one.
*/ if (cpu_is_pxa27x() &&
(cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000))
pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); else
cmd->error = -EILSEQ;
}
pxamci_disable_irq(host, END_CMD_RES); if (host->data && !cmd->error) {
pxamci_enable_irq(host, DATA_TRAN_DONE); /* * workaround for erratum #91, if doing write * enable DMA late
*/ if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
dma_async_issue_pending(host->dma_chan_tx);
} else {
pxamci_finish_request(host, host->mrq);
}
/* * There appears to be a hardware design bug here. There seems to * be no way to find out how much data was transferred to the card. * This means that if there was an error on any block, we mark all * data blocks as being in error.
*/ if (!data->error)
data->bytes_xfered = data->blocks * data->blksz; else
data->bytes_xfered = 0;
if (host->use_ro_gpio) return mmc_gpio_get_ro(mmc); if (host->pdata && host->pdata->get_ro) return !!host->pdata->get_ro(mmc_dev(mmc)); /* * Board doesn't support read only detection; let the mmc core * decide what to do.
*/ return -ENOSYS;
}
if (host->clkrt == CLKRT_OFF)
clk_prepare_enable(host->clk);
if (ios->clock == 26000000) { /* to support 26MHz */
host->clkrt = 7;
} else { /* to handle (19.5MHz, 26MHz) */ if (!clk)
clk = 1;
/* * clk might result in a lower divisor than we * desire. check for that condition and adjust * as appropriate.
*/ if (rate / clk > ios->clock)
clk <<= 1;
host->clkrt = fls(clk) - 1;
}
/* * we write clkrt on the next command
*/
} else {
pxamci_stop_clock(host); if (host->clkrt != CLKRT_OFF) {
host->clkrt = CLKRT_OFF;
clk_disable_unprepare(host->clk);
}
}
if (host->power_mode != ios->power_mode) { int ret;
host->power_mode = ios->power_mode;
ret = pxamci_set_power(host, ios->power_mode, ios->vdd); if (ret) {
dev_err(mmc_dev(mmc), "unable to set power\n"); /* * The .set_ios() function in the mmc_host_ops * struct return void, and failing to set the * power should be rare so we print an error and * return here.
*/ return;
}
if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMDAT_INIT;
}
/* FIXME: should we pass detection delay to debounce? */
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); if (ret && ret != -ENOENT) return dev_err_probe(dev, ret, "Failed requesting gpio_cd\n");
if (!host->pdata->gpio_card_ro_invert)
mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0); if (ret && ret != -ENOENT) return dev_err_probe(dev, ret, "Failed requesting gpio_ro\n");
if (!ret)
host->use_ro_gpio = true;
if (host->pdata->init)
host->pdata->init(dev, pxamci_detect_irq, mmc);
if (host->power && host->pdata->setpower)
dev_warn(dev, "gpio_power and setpower() both defined\n"); if (host->use_ro_gpio && host->pdata->get_ro)
dev_warn(dev, "gpio_ro and get_ro() both defined\n");
}
ret = mmc_add_host(mmc); if (ret) { if (host->pdata && host->pdata->exit)
host->pdata->exit(dev, mmc);
}
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.