aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r--drivers/mmc/host/sdhci.c319
1 files changed, 208 insertions, 111 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index accb592764ed..9234be2226e7 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -48,35 +48,35 @@ static void sdhci_dumpregs(struct sdhci_host *host)
printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
- readl(host->ioaddr + SDHCI_DMA_ADDRESS),
- readw(host->ioaddr + SDHCI_HOST_VERSION));
+ sdhci_readl(host, SDHCI_DMA_ADDRESS),
+ sdhci_readw(host, SDHCI_HOST_VERSION));
printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
- readw(host->ioaddr + SDHCI_BLOCK_SIZE),
- readw(host->ioaddr + SDHCI_BLOCK_COUNT));
+ sdhci_readw(host, SDHCI_BLOCK_SIZE),
+ sdhci_readw(host, SDHCI_BLOCK_COUNT));
printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
- readl(host->ioaddr + SDHCI_ARGUMENT),
- readw(host->ioaddr + SDHCI_TRANSFER_MODE));
+ sdhci_readl(host, SDHCI_ARGUMENT),
+ sdhci_readw(host, SDHCI_TRANSFER_MODE));
printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
- readl(host->ioaddr + SDHCI_PRESENT_STATE),
- readb(host->ioaddr + SDHCI_HOST_CONTROL));
+ sdhci_readl(host, SDHCI_PRESENT_STATE),
+ sdhci_readb(host, SDHCI_HOST_CONTROL));
printk(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
- readb(host->ioaddr + SDHCI_POWER_CONTROL),
- readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
+ sdhci_readb(host, SDHCI_POWER_CONTROL),
+ sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
- readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL),
- readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
+ sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
+ sdhci_readw(host, SDHCI_CLOCK_CONTROL));
printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
- readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
- readl(host->ioaddr + SDHCI_INT_STATUS));
+ sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
+ sdhci_readl(host, SDHCI_INT_STATUS));
printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
- readl(host->ioaddr + SDHCI_INT_ENABLE),
- readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
+ sdhci_readl(host, SDHCI_INT_ENABLE),
+ sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
- readw(host->ioaddr + SDHCI_ACMD12_ERR),
- readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
+ sdhci_readw(host, SDHCI_ACMD12_ERR),
+ sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n",
- readl(host->ioaddr + SDHCI_CAPABILITIES),
- readl(host->ioaddr + SDHCI_MAX_CURRENT));
+ sdhci_readl(host, SDHCI_CAPABILITIES),
+ sdhci_readl(host, SDHCI_MAX_CURRENT));
printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
}
@@ -87,17 +87,65 @@ static void sdhci_dumpregs(struct sdhci_host *host)
* *
\*****************************************************************************/
+static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+{
+ u32 ier;
+
+ ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+ ier &= ~clear;
+ ier |= set;
+ sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
+{
+ sdhci_clear_set_irqs(host, 0, irqs);
+}
+
+static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
+{
+ sdhci_clear_set_irqs(host, irqs, 0);
+}
+
+static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
+{
+ u32 irqs = SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT;
+
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+ return;
+
+ if (enable)
+ sdhci_unmask_irqs(host, irqs);
+ else
+ sdhci_mask_irqs(host, irqs);
+}
+
+static void sdhci_enable_card_detection(struct sdhci_host *host)
+{
+ sdhci_set_card_detection(host, true);
+}
+
+static void sdhci_disable_card_detection(struct sdhci_host *host)
+{
+ sdhci_set_card_detection(host, false);
+}
+
static void sdhci_reset(struct sdhci_host *host, u8 mask)
{
unsigned long timeout;
+ u32 uninitialized_var(ier);
if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
- if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+ if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
SDHCI_CARD_PRESENT))
return;
}
- writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
+ if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
+ ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+
+ sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
if (mask & SDHCI_RESET_ALL)
host->clock = 0;
@@ -106,7 +154,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
timeout = 100;
/* hw clears the bit when it's done */
- while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
+ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
if (timeout == 0) {
printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
@@ -116,42 +164,44 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
timeout--;
mdelay(1);
}
+
+ if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
+ sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
}
static void sdhci_init(struct sdhci_host *host)
{
- u32 intmask;
-
sdhci_reset(host, SDHCI_RESET_ALL);
- intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+ sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
+ SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
- SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
- SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
- SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |
- SDHCI_INT_ADMA_ERROR;
+ SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+}
- writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
- writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+static void sdhci_reinit(struct sdhci_host *host)
+{
+ sdhci_init(host);
+ sdhci_enable_card_detection(host);
}
static void sdhci_activate_led(struct sdhci_host *host)
{
u8 ctrl;
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl |= SDHCI_CTRL_LED;
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static void sdhci_deactivate_led(struct sdhci_host *host)
{
u8 ctrl;
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_LED;
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
#ifdef SDHCI_USE_LEDS_CLASS
@@ -205,7 +255,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
while (len) {
if (chunk == 0) {
- scratch = readl(host->ioaddr + SDHCI_BUFFER);
+ scratch = sdhci_readl(host, SDHCI_BUFFER);
chunk = 4;
}
@@ -257,7 +307,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
len--;
if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
- writel(scratch, host->ioaddr + SDHCI_BUFFER);
+ sdhci_writel(host, scratch, SDHCI_BUFFER);
chunk = 0;
scratch = 0;
}
@@ -292,7 +342,10 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
(host->data->blocks == 1))
mask = ~0;
- while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+ while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
+ if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
+ udelay(100);
+
if (host->data->flags & MMC_DATA_READ)
sdhci_read_block_pio(host);
else
@@ -561,6 +614,17 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
return count;
}
+static void sdhci_set_transfer_irqs(struct sdhci_host *host)
+{
+ u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
+ u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
+
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
+ else
+ sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
+}
+
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
{
u8 count;
@@ -581,7 +645,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
host->data_early = 0;
count = sdhci_calc_timeout(host, data);
- writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
+ sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
if (host->flags & SDHCI_USE_DMA)
host->flags |= SDHCI_REQ_USE_DMA;
@@ -661,8 +725,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
WARN_ON(1);
host->flags &= ~SDHCI_REQ_USE_DMA;
} else {
- writel(host->adma_addr,
- host->ioaddr + SDHCI_ADMA_ADDRESS);
+ sdhci_writel(host, host->adma_addr,
+ SDHCI_ADMA_ADDRESS);
}
} else {
int sg_cnt;
@@ -681,8 +745,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
host->flags &= ~SDHCI_REQ_USE_DMA;
} else {
WARN_ON(sg_cnt != 1);
- writel(sg_dma_address(data->sg),
- host->ioaddr + SDHCI_DMA_ADDRESS);
+ sdhci_writel(host, sg_dma_address(data->sg),
+ SDHCI_DMA_ADDRESS);
}
}
}
@@ -693,14 +757,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
* is ADMA.
*/
if (host->version >= SDHCI_SPEC_200) {
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
if ((host->flags & SDHCI_REQ_USE_DMA) &&
(host->flags & SDHCI_USE_ADMA))
ctrl |= SDHCI_CTRL_ADMA32;
else
ctrl |= SDHCI_CTRL_SDMA;
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
if (!(host->flags & SDHCI_REQ_USE_DMA)) {
@@ -709,10 +773,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
host->blocks = data->blocks;
}
+ sdhci_set_transfer_irqs(host);
+
/* We do not handle DMA boundaries, so set it to max (512 KiB) */
- writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
- host->ioaddr + SDHCI_BLOCK_SIZE);
- writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE);
+ sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
}
static void sdhci_set_transfer_mode(struct sdhci_host *host,
@@ -733,7 +798,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
if (host->flags & SDHCI_REQ_USE_DMA)
mode |= SDHCI_TRNS_DMA;
- writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
+ sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
}
static void sdhci_finish_data(struct sdhci_host *host)
@@ -802,7 +867,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if (host->mrq->data && (cmd == host->mrq->data->stop))
mask &= ~SDHCI_DATA_INHIBIT;
- while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+ while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
if (timeout == 0) {
printk(KERN_ERR "%s: Controller never released "
"inhibit bit(s).\n", mmc_hostname(host->mmc));
@@ -821,7 +886,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_prepare_data(host, cmd->data);
- writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
+ sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
sdhci_set_transfer_mode(host, cmd->data);
@@ -849,8 +914,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if (cmd->data)
flags |= SDHCI_CMD_DATA;
- writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
- host->ioaddr + SDHCI_COMMAND);
+ sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
}
static void sdhci_finish_command(struct sdhci_host *host)
@@ -863,15 +927,15 @@ static void sdhci_finish_command(struct sdhci_host *host)
if (host->cmd->flags & MMC_RSP_136) {
/* CRC is stripped so we need to do some shifting. */
for (i = 0;i < 4;i++) {
- host->cmd->resp[i] = readl(host->ioaddr +
+ host->cmd->resp[i] = sdhci_readl(host,
SDHCI_RESPONSE + (3-i)*4) << 8;
if (i != 3)
host->cmd->resp[i] |=
- readb(host->ioaddr +
+ sdhci_readb(host,
SDHCI_RESPONSE + (3-i)*4-1);
}
} else {
- host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
+ host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
}
}
@@ -895,7 +959,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == host->clock)
return;
- writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+ if (host->ops->set_clock) {
+ host->ops->set_clock(host, clock);
+ if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
+ return;
+ }
+
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0)
goto out;
@@ -908,11 +978,11 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
clk = div << SDHCI_DIVIDER_SHIFT;
clk |= SDHCI_CLOCK_INT_EN;
- writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
/* Wait max 10 ms */
timeout = 10;
- while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
+ while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
printk(KERN_ERR "%s: Internal clock never "
@@ -925,7 +995,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
}
clk |= SDHCI_CLOCK_CARD_EN;
- writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
out:
host->clock = clock;
@@ -939,7 +1009,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
return;
if (power == (unsigned short)-1) {
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
goto out;
}
@@ -948,7 +1018,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
* a new value. Some controllers don't seem to like this though.
*/
if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
pwr = SDHCI_POWER_ON;
@@ -973,10 +1043,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
* and set turn on power at the same time, so set the voltage first.
*/
if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
- writeb(pwr & ~SDHCI_POWER_ON,
- host->ioaddr + SDHCI_POWER_CONTROL);
+ sdhci_writeb(host, pwr & ~SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
- writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
out:
host->power = power;
@@ -991,6 +1060,7 @@ out:
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
+ bool present;
unsigned long flags;
host = mmc_priv(mmc);
@@ -1005,8 +1075,14 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
- if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)
- || (host->flags & SDHCI_DEVICE_DEAD)) {
+ /* If polling, assume that the card is always present. */
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+ present = true;
+ else
+ present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+ SDHCI_CARD_PRESENT;
+
+ if (!present || host->flags & SDHCI_DEVICE_DEAD) {
host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
} else
@@ -1034,8 +1110,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* Should clear out any weird states.
*/
if (ios->power_mode == MMC_POWER_OFF) {
- writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
- sdhci_init(host);
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+ sdhci_reinit(host);
}
sdhci_set_clock(host, ios->clock);
@@ -1045,7 +1121,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
sdhci_set_power(host, ios->vdd);
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (ios->bus_width == MMC_BUS_WIDTH_4)
ctrl |= SDHCI_CTRL_4BITBUS;
@@ -1057,7 +1133,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
ctrl &= ~SDHCI_CTRL_HISPD;
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
/*
* Some (ENE) controllers go apeshit on some ios operation,
@@ -1085,10 +1161,12 @@ static int sdhci_get_ro(struct mmc_host *mmc)
if (host->flags & SDHCI_DEVICE_DEAD)
present = 0;
else
- present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+ present = sdhci_readl(host, SDHCI_PRESENT_STATE);
spin_unlock_irqrestore(&host->lock, flags);
+ if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
+ return !!(present & SDHCI_WRITE_PROTECT);
return !(present & SDHCI_WRITE_PROTECT);
}
@@ -1096,7 +1174,6 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sdhci_host *host;
unsigned long flags;
- u32 ier;
host = mmc_priv(mmc);
@@ -1105,15 +1182,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
- ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
-
- ier &= ~SDHCI_INT_CARD_INT;
if (enable)
- ier |= SDHCI_INT_CARD_INT;
-
- writel(ier, host->ioaddr + SDHCI_INT_ENABLE);
- writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-
+ sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
+ else
+ sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
out:
mmiowb();
@@ -1142,7 +1214,7 @@ static void sdhci_tasklet_card(unsigned long param)
spin_lock_irqsave(&host->lock, flags);
- if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+ if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
if (host->mrq) {
printk(KERN_ERR "%s: Card removed during transfer!\n",
mmc_hostname(host->mmc));
@@ -1346,8 +1418,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
* we need to at least restart the transfer.
*/
if (intmask & SDHCI_INT_DMA_END)
- writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
- host->ioaddr + SDHCI_DMA_ADDRESS);
+ sdhci_writel(host, sdhci_readl(host, SDHCI_DMA_ADDRESS),
+ SDHCI_DMA_ADDRESS);
if (intmask & SDHCI_INT_DATA_END) {
if (host->cmd) {
@@ -1373,7 +1445,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
spin_lock(&host->lock);
- intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
+ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
if (!intmask || intmask == 0xffffffff) {
result = IRQ_NONE;
@@ -1384,22 +1456,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
mmc_hostname(host->mmc), intmask);
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
- host->ioaddr + SDHCI_INT_STATUS);
+ sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
tasklet_schedule(&host->card_tasklet);
}
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
if (intmask & SDHCI_INT_CMD_MASK) {
- writel(intmask & SDHCI_INT_CMD_MASK,
- host->ioaddr + SDHCI_INT_STATUS);
+ sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
+ SDHCI_INT_STATUS);
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
}
if (intmask & SDHCI_INT_DATA_MASK) {
- writel(intmask & SDHCI_INT_DATA_MASK,
- host->ioaddr + SDHCI_INT_STATUS);
+ sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
+ SDHCI_INT_STATUS);
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
}
@@ -1410,7 +1482,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
if (intmask & SDHCI_INT_BUS_POWER) {
printk(KERN_ERR "%s: Card is consuming too much power!\n",
mmc_hostname(host->mmc));
- writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
+ sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
}
intmask &= ~SDHCI_INT_BUS_POWER;
@@ -1425,7 +1497,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
mmc_hostname(host->mmc), intmask);
sdhci_dumpregs(host);
- writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
+ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
}
result = IRQ_HANDLED;
@@ -1455,6 +1527,8 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
{
int ret;
+ sdhci_disable_card_detection(host);
+
ret = mmc_suspend_host(host->mmc, state);
if (ret)
return ret;
@@ -1487,6 +1561,8 @@ int sdhci_resume_host(struct sdhci_host *host)
if (ret)
return ret;
+ sdhci_enable_card_detection(host);
+
return 0;
}
@@ -1537,7 +1613,7 @@ int sdhci_add_host(struct sdhci_host *host)
sdhci_reset(host, SDHCI_RESET_ALL);
- host->version = readw(host->ioaddr + SDHCI_HOST_VERSION);
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
host->version = (host->version & SDHCI_SPEC_VER_MASK)
>> SDHCI_SPEC_VER_SHIFT;
if (host->version > SDHCI_SPEC_200) {
@@ -1546,7 +1622,7 @@ int sdhci_add_host(struct sdhci_host *host)
host->version);
}
- caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
host->flags |= SDHCI_USE_DMA;
@@ -1614,19 +1690,27 @@ int sdhci_add_host(struct sdhci_host *host)
host->max_clk =
(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+ host->max_clk *= 1000000;
if (host->max_clk == 0) {
- printk(KERN_ERR "%s: Hardware doesn't specify base clock "
- "frequency.\n", mmc_hostname(mmc));
- return -ENODEV;
+ if (!host->ops->get_max_clock) {
+ printk(KERN_ERR
+ "%s: Hardware doesn't specify base clock "
+ "frequency.\n", mmc_hostname(mmc));
+ return -ENODEV;
+ }
+ host->max_clk = host->ops->get_max_clock(host);
}
- host->max_clk *= 1000000;
host->timeout_clk =
(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
if (host->timeout_clk == 0) {
- printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
- "frequency.\n", mmc_hostname(mmc));
- return -ENODEV;
+ if (!host->ops->get_timeout_clock) {
+ printk(KERN_ERR
+ "%s: Hardware doesn't specify timeout clock "
+ "frequency.\n", mmc_hostname(mmc));
+ return -ENODEV;
+ }
+ host->timeout_clk = host->ops->get_timeout_clock(host);
}
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000;
@@ -1642,6 +1726,9 @@ int sdhci_add_host(struct sdhci_host *host)
if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
@@ -1690,13 +1777,19 @@ int sdhci_add_host(struct sdhci_host *host)
* Maximum block size. This varies from controller to controller and
* is specified in the capabilities register.
*/
- mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
- if (mmc->max_blk_size >= 3) {
- printk(KERN_WARNING "%s: Invalid maximum block size, "
- "assuming 512 bytes\n", mmc_hostname(mmc));
- mmc->max_blk_size = 512;
- } else
- mmc->max_blk_size = 512 << mmc->max_blk_size;
+ if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
+ mmc->max_blk_size = 2;
+ } else {
+ mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >>
+ SDHCI_MAX_BLOCK_SHIFT;
+ if (mmc->max_blk_size >= 3) {
+ printk(KERN_WARNING "%s: Invalid maximum block size, "
+ "assuming 512 bytes\n", mmc_hostname(mmc));
+ mmc->max_blk_size = 0;
+ }
+ }
+
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
/*
* Maximum block count.
@@ -1746,6 +1839,8 @@ int sdhci_add_host(struct sdhci_host *host)
(host->flags & SDHCI_USE_ADMA)?"A":"",
(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
+ sdhci_enable_card_detection(host);
+
return 0;
#ifdef SDHCI_USE_LEDS_CLASS
@@ -1782,6 +1877,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
spin_unlock_irqrestore(&host->lock, flags);
}
+ sdhci_disable_card_detection(host);
+
mmc_remove_host(host->mmc);
#ifdef SDHCI_USE_LEDS_CLASS
@@ -1838,7 +1935,7 @@ module_exit(sdhci_drv_exit);
module_param(debug_quirks, uint, 0444);
-MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver");
MODULE_LICENSE("GPL");