|
@@ -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 ": ============== REGISTER DUMP ==============\n");
|
|
|
|
|
|
printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\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",
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
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");
|
|
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)
|
|
static void sdhci_reset(struct sdhci_host *host, u8 mask)
|
|
{
|
|
{
|
|
unsigned long timeout;
|
|
unsigned long timeout;
|
|
|
|
+ u32 uninitialized_var(ier);
|
|
|
|
|
|
if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
|
|
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))
|
|
SDHCI_CARD_PRESENT))
|
|
return;
|
|
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)
|
|
if (mask & SDHCI_RESET_ALL)
|
|
host->clock = 0;
|
|
host->clock = 0;
|
|
@@ -106,7 +154,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
|
|
timeout = 100;
|
|
timeout = 100;
|
|
|
|
|
|
/* hw clears the bit when it's done */
|
|
/* 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) {
|
|
if (timeout == 0) {
|
|
printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
|
|
printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
|
|
mmc_hostname(host->mmc), (int)mask);
|
|
mmc_hostname(host->mmc), (int)mask);
|
|
@@ -116,42 +164,44 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
|
|
timeout--;
|
|
timeout--;
|
|
mdelay(1);
|
|
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)
|
|
static void sdhci_init(struct sdhci_host *host)
|
|
{
|
|
{
|
|
- u32 intmask;
|
|
|
|
-
|
|
|
|
sdhci_reset(host, SDHCI_RESET_ALL);
|
|
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_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
|
|
SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
|
|
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)
|
|
static void sdhci_activate_led(struct sdhci_host *host)
|
|
{
|
|
{
|
|
u8 ctrl;
|
|
u8 ctrl;
|
|
|
|
|
|
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
|
|
|
|
|
|
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
|
ctrl |= SDHCI_CTRL_LED;
|
|
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)
|
|
static void sdhci_deactivate_led(struct sdhci_host *host)
|
|
{
|
|
{
|
|
u8 ctrl;
|
|
u8 ctrl;
|
|
|
|
|
|
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
|
|
|
|
|
|
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
|
ctrl &= ~SDHCI_CTRL_LED;
|
|
ctrl &= ~SDHCI_CTRL_LED;
|
|
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
|
|
|
|
|
|
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef SDHCI_USE_LEDS_CLASS
|
|
#ifdef SDHCI_USE_LEDS_CLASS
|
|
@@ -205,7 +255,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
|
|
|
|
|
|
while (len) {
|
|
while (len) {
|
|
if (chunk == 0) {
|
|
if (chunk == 0) {
|
|
- scratch = readl(host->ioaddr + SDHCI_BUFFER);
|
|
|
|
|
|
+ scratch = sdhci_readl(host, SDHCI_BUFFER);
|
|
chunk = 4;
|
|
chunk = 4;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -257,7 +307,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
|
|
len--;
|
|
len--;
|
|
|
|
|
|
if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
|
|
if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
|
|
- writel(scratch, host->ioaddr + SDHCI_BUFFER);
|
|
|
|
|
|
+ sdhci_writel(host, scratch, SDHCI_BUFFER);
|
|
chunk = 0;
|
|
chunk = 0;
|
|
scratch = 0;
|
|
scratch = 0;
|
|
}
|
|
}
|
|
@@ -292,7 +342,10 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
|
|
(host->data->blocks == 1))
|
|
(host->data->blocks == 1))
|
|
mask = ~0;
|
|
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)
|
|
if (host->data->flags & MMC_DATA_READ)
|
|
sdhci_read_block_pio(host);
|
|
sdhci_read_block_pio(host);
|
|
else
|
|
else
|
|
@@ -561,6 +614,17 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
|
|
return count;
|
|
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)
|
|
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
|
|
{
|
|
{
|
|
u8 count;
|
|
u8 count;
|
|
@@ -581,7 +645,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
|
|
host->data_early = 0;
|
|
host->data_early = 0;
|
|
|
|
|
|
count = sdhci_calc_timeout(host, data);
|
|
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)
|
|
if (host->flags & SDHCI_USE_DMA)
|
|
host->flags |= SDHCI_REQ_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);
|
|
WARN_ON(1);
|
|
host->flags &= ~SDHCI_REQ_USE_DMA;
|
|
host->flags &= ~SDHCI_REQ_USE_DMA;
|
|
} else {
|
|
} else {
|
|
- writel(host->adma_addr,
|
|
|
|
- host->ioaddr + SDHCI_ADMA_ADDRESS);
|
|
|
|
|
|
+ sdhci_writel(host, host->adma_addr,
|
|
|
|
+ SDHCI_ADMA_ADDRESS);
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
int sg_cnt;
|
|
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;
|
|
host->flags &= ~SDHCI_REQ_USE_DMA;
|
|
} else {
|
|
} else {
|
|
WARN_ON(sg_cnt != 1);
|
|
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.
|
|
* is ADMA.
|
|
*/
|
|
*/
|
|
if (host->version >= SDHCI_SPEC_200) {
|
|
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;
|
|
ctrl &= ~SDHCI_CTRL_DMA_MASK;
|
|
if ((host->flags & SDHCI_REQ_USE_DMA) &&
|
|
if ((host->flags & SDHCI_REQ_USE_DMA) &&
|
|
(host->flags & SDHCI_USE_ADMA))
|
|
(host->flags & SDHCI_USE_ADMA))
|
|
ctrl |= SDHCI_CTRL_ADMA32;
|
|
ctrl |= SDHCI_CTRL_ADMA32;
|
|
else
|
|
else
|
|
ctrl |= SDHCI_CTRL_SDMA;
|
|
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)) {
|
|
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;
|
|
host->blocks = data->blocks;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ sdhci_set_transfer_irqs(host);
|
|
|
|
+
|
|
/* We do not handle DMA boundaries, so set it to max (512 KiB) */
|
|
/* 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,
|
|
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)
|
|
if (host->flags & SDHCI_REQ_USE_DMA)
|
|
mode |= SDHCI_TRNS_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)
|
|
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))
|
|
if (host->mrq->data && (cmd == host->mrq->data->stop))
|
|
mask &= ~SDHCI_DATA_INHIBIT;
|
|
mask &= ~SDHCI_DATA_INHIBIT;
|
|
|
|
|
|
- while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
|
|
|
|
|
|
+ while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
|
|
if (timeout == 0) {
|
|
if (timeout == 0) {
|
|
printk(KERN_ERR "%s: Controller never released "
|
|
printk(KERN_ERR "%s: Controller never released "
|
|
"inhibit bit(s).\n", mmc_hostname(host->mmc));
|
|
"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);
|
|
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);
|
|
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)
|
|
if (cmd->data)
|
|
flags |= SDHCI_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)
|
|
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) {
|
|
if (host->cmd->flags & MMC_RSP_136) {
|
|
/* CRC is stripped so we need to do some shifting. */
|
|
/* CRC is stripped so we need to do some shifting. */
|
|
for (i = 0;i < 4;i++) {
|
|
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;
|
|
SDHCI_RESPONSE + (3-i)*4) << 8;
|
|
if (i != 3)
|
|
if (i != 3)
|
|
host->cmd->resp[i] |=
|
|
host->cmd->resp[i] |=
|
|
- readb(host->ioaddr +
|
|
|
|
|
|
+ sdhci_readb(host,
|
|
SDHCI_RESPONSE + (3-i)*4-1);
|
|
SDHCI_RESPONSE + (3-i)*4-1);
|
|
}
|
|
}
|
|
} else {
|
|
} 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)
|
|
if (clock == host->clock)
|
|
return;
|
|
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)
|
|
if (clock == 0)
|
|
goto out;
|
|
goto out;
|
|
@@ -908,11 +978,11 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
|
|
|
|
|
clk = div << SDHCI_DIVIDER_SHIFT;
|
|
clk = div << SDHCI_DIVIDER_SHIFT;
|
|
clk |= SDHCI_CLOCK_INT_EN;
|
|
clk |= SDHCI_CLOCK_INT_EN;
|
|
- writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
|
|
|
|
|
|
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
|
|
|
|
|
/* Wait max 10 ms */
|
|
/* Wait max 10 ms */
|
|
timeout = 10;
|
|
timeout = 10;
|
|
- while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
|
|
|
|
|
|
+ while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
|
|
& SDHCI_CLOCK_INT_STABLE)) {
|
|
& SDHCI_CLOCK_INT_STABLE)) {
|
|
if (timeout == 0) {
|
|
if (timeout == 0) {
|
|
printk(KERN_ERR "%s: Internal clock never "
|
|
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;
|
|
clk |= SDHCI_CLOCK_CARD_EN;
|
|
- writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
|
|
|
|
|
|
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
|
|
|
|
|
out:
|
|
out:
|
|
host->clock = clock;
|
|
host->clock = clock;
|
|
@@ -939,7 +1009,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
|
|
return;
|
|
return;
|
|
|
|
|
|
if (power == (unsigned short)-1) {
|
|
if (power == (unsigned short)-1) {
|
|
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
|
|
|
|
|
|
+ sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
|
|
goto out;
|
|
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.
|
|
* a new value. Some controllers don't seem to like this though.
|
|
*/
|
|
*/
|
|
if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
|
|
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;
|
|
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.
|
|
* and set turn on power at the same time, so set the voltage first.
|
|
*/
|
|
*/
|
|
if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
|
|
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:
|
|
out:
|
|
host->power = power;
|
|
host->power = power;
|
|
@@ -991,6 +1060,7 @@ out:
|
|
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|
{
|
|
{
|
|
struct sdhci_host *host;
|
|
struct sdhci_host *host;
|
|
|
|
+ bool present;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
host = mmc_priv(mmc);
|
|
host = mmc_priv(mmc);
|
|
@@ -1005,8 +1075,14 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|
|
|
|
|
host->mrq = 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;
|
|
host->mrq->cmd->error = -ENOMEDIUM;
|
|
tasklet_schedule(&host->finish_tasklet);
|
|
tasklet_schedule(&host->finish_tasklet);
|
|
} else
|
|
} else
|
|
@@ -1034,8 +1110,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|
* Should clear out any weird states.
|
|
* Should clear out any weird states.
|
|
*/
|
|
*/
|
|
if (ios->power_mode == MMC_POWER_OFF) {
|
|
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);
|
|
sdhci_set_clock(host, ios->clock);
|
|
@@ -1045,7 +1121,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|
else
|
|
else
|
|
sdhci_set_power(host, ios->vdd);
|
|
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)
|
|
if (ios->bus_width == MMC_BUS_WIDTH_4)
|
|
ctrl |= SDHCI_CTRL_4BITBUS;
|
|
ctrl |= SDHCI_CTRL_4BITBUS;
|
|
@@ -1057,7 +1133,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|
else
|
|
else
|
|
ctrl &= ~SDHCI_CTRL_HISPD;
|
|
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,
|
|
* 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)
|
|
if (host->flags & SDHCI_DEVICE_DEAD)
|
|
present = 0;
|
|
present = 0;
|
|
else
|
|
else
|
|
- present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
|
|
|
|
|
|
+ present = sdhci_readl(host, SDHCI_PRESENT_STATE);
|
|
|
|
|
|
spin_unlock_irqrestore(&host->lock, flags);
|
|
spin_unlock_irqrestore(&host->lock, flags);
|
|
|
|
|
|
|
|
+ if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
|
|
|
|
+ return !!(present & SDHCI_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;
|
|
struct sdhci_host *host;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
- u32 ier;
|
|
|
|
|
|
|
|
host = mmc_priv(mmc);
|
|
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)
|
|
if (host->flags & SDHCI_DEVICE_DEAD)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
|
|
|
|
-
|
|
|
|
- ier &= ~SDHCI_INT_CARD_INT;
|
|
|
|
if (enable)
|
|
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:
|
|
out:
|
|
mmiowb();
|
|
mmiowb();
|
|
|
|
|
|
@@ -1142,7 +1214,7 @@ static void sdhci_tasklet_card(unsigned long param)
|
|
|
|
|
|
spin_lock_irqsave(&host->lock, flags);
|
|
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) {
|
|
if (host->mrq) {
|
|
printk(KERN_ERR "%s: Card removed during transfer!\n",
|
|
printk(KERN_ERR "%s: Card removed during transfer!\n",
|
|
mmc_hostname(host->mmc));
|
|
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.
|
|
* we need to at least restart the transfer.
|
|
*/
|
|
*/
|
|
if (intmask & SDHCI_INT_DMA_END)
|
|
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 (intmask & SDHCI_INT_DATA_END) {
|
|
if (host->cmd) {
|
|
if (host->cmd) {
|
|
@@ -1373,7 +1445,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
|
|
|
|
|
|
spin_lock(&host->lock);
|
|
spin_lock(&host->lock);
|
|
|
|
|
|
- intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
|
|
|
|
|
|
+ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
|
|
|
|
|
|
if (!intmask || intmask == 0xffffffff) {
|
|
if (!intmask || intmask == 0xffffffff) {
|
|
result = IRQ_NONE;
|
|
result = IRQ_NONE;
|
|
@@ -1384,22 +1456,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
|
|
mmc_hostname(host->mmc), intmask);
|
|
mmc_hostname(host->mmc), intmask);
|
|
|
|
|
|
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
|
|
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);
|
|
tasklet_schedule(&host->card_tasklet);
|
|
}
|
|
}
|
|
|
|
|
|
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
|
|
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
|
|
|
|
|
|
if (intmask & SDHCI_INT_CMD_MASK) {
|
|
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);
|
|
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
|
|
}
|
|
}
|
|
|
|
|
|
if (intmask & SDHCI_INT_DATA_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);
|
|
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) {
|
|
if (intmask & SDHCI_INT_BUS_POWER) {
|
|
printk(KERN_ERR "%s: Card is consuming too much power!\n",
|
|
printk(KERN_ERR "%s: Card is consuming too much power!\n",
|
|
mmc_hostname(host->mmc));
|
|
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;
|
|
intmask &= ~SDHCI_INT_BUS_POWER;
|
|
@@ -1425,7 +1497,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
|
|
mmc_hostname(host->mmc), intmask);
|
|
mmc_hostname(host->mmc), intmask);
|
|
sdhci_dumpregs(host);
|
|
sdhci_dumpregs(host);
|
|
|
|
|
|
- writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
|
|
|
|
|
|
+ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
|
|
}
|
|
}
|
|
|
|
|
|
result = IRQ_HANDLED;
|
|
result = IRQ_HANDLED;
|
|
@@ -1455,6 +1527,8 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
+ sdhci_disable_card_detection(host);
|
|
|
|
+
|
|
ret = mmc_suspend_host(host->mmc, state);
|
|
ret = mmc_suspend_host(host->mmc, state);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
@@ -1487,6 +1561,8 @@ int sdhci_resume_host(struct sdhci_host *host)
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
|
|
+ sdhci_enable_card_detection(host);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1537,7 +1613,7 @@ int sdhci_add_host(struct sdhci_host *host)
|
|
|
|
|
|
sdhci_reset(host, SDHCI_RESET_ALL);
|
|
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)
|
|
host->version = (host->version & SDHCI_SPEC_VER_MASK)
|
|
>> SDHCI_SPEC_VER_SHIFT;
|
|
>> SDHCI_SPEC_VER_SHIFT;
|
|
if (host->version > SDHCI_SPEC_200) {
|
|
if (host->version > SDHCI_SPEC_200) {
|
|
@@ -1546,7 +1622,7 @@ int sdhci_add_host(struct sdhci_host *host)
|
|
host->version);
|
|
host->version);
|
|
}
|
|
}
|
|
|
|
|
|
- caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
|
|
|
|
|
|
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
|
|
|
|
|
if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
|
|
if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
|
|
host->flags |= SDHCI_USE_DMA;
|
|
host->flags |= SDHCI_USE_DMA;
|
|
@@ -1614,19 +1690,27 @@ int sdhci_add_host(struct sdhci_host *host)
|
|
|
|
|
|
host->max_clk =
|
|
host->max_clk =
|
|
(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
|
|
(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
|
|
|
|
+ host->max_clk *= 1000000;
|
|
if (host->max_clk == 0) {
|
|
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 =
|
|
host->timeout_clk =
|
|
(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
|
|
(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
|
|
if (host->timeout_clk == 0) {
|
|
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)
|
|
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
|
|
host->timeout_clk *= 1000;
|
|
host->timeout_clk *= 1000;
|
|
@@ -1642,6 +1726,9 @@ int sdhci_add_host(struct sdhci_host *host)
|
|
if (caps & SDHCI_CAN_DO_HISPD)
|
|
if (caps & SDHCI_CAN_DO_HISPD)
|
|
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
|
|
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
|
|
|
|
|
|
|
|
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
|
|
|
|
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
|
|
|
|
+
|
|
mmc->ocr_avail = 0;
|
|
mmc->ocr_avail = 0;
|
|
if (caps & SDHCI_CAN_VDD_330)
|
|
if (caps & SDHCI_CAN_VDD_330)
|
|
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
|
|
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
|
|
* Maximum block size. This varies from controller to controller and
|
|
* is specified in the capabilities register.
|
|
* 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.
|
|
* 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_ADMA)?"A":"",
|
|
(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
|
|
(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
|
|
|
|
|
|
|
|
+ sdhci_enable_card_detection(host);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
#ifdef SDHCI_USE_LEDS_CLASS
|
|
#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);
|
|
spin_unlock_irqrestore(&host->lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ sdhci_disable_card_detection(host);
|
|
|
|
+
|
|
mmc_remove_host(host->mmc);
|
|
mmc_remove_host(host->mmc);
|
|
|
|
|
|
#ifdef SDHCI_USE_LEDS_CLASS
|
|
#ifdef SDHCI_USE_LEDS_CLASS
|