diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-28 14:16:11 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-28 14:16:11 -0700 |
commit | 46b51ea2099fa2082342e52b8284aa828429b80b (patch) | |
tree | 0a0d7bfe1aff036c86a2e7beacbd91398008bfb6 /drivers/mmc/host/dw_mmc.c | |
parent | 1fdb24e969110fafea36d3b393bea438f702c87f (diff) | |
parent | a6029e1f75bb484c1f5bc68b6a8572e4024795bc (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (83 commits)
mmc: fix compile error when CONFIG_BLOCK is not enabled
mmc: core: Cleanup eMMC4.5 conditionals
mmc: omap_hsmmc: if multiblock reads are broken, disable them
mmc: core: add workaround for controllers with broken multiblock reads
mmc: core: Prevent too long response times for suspend
mmc: recognise SDIO cards with SDIO_CCCR_REV 3.00
mmc: sd: Handle SD3.0 cards not supporting UHS-I bus speed mode
mmc: core: support HPI send command
mmc: core: Add cache control for eMMC4.5 device
mmc: core: Modify the timeout value for writing power class
mmc: core: new discard feature support at eMMC v4.5
mmc: core: mmc sanitize feature support for v4.5
mmc: dw_mmc: modify DATA register offset
mmc: sdhci-pci: add flag for devices that can support runtime PM
mmc: omap_hsmmc: ensure pbias configuration is always done
mmc: core: Add Power Off Notify Feature eMMC 4.5
mmc: sdhci-s3c: fix potential NULL dereference
mmc: replace printk with appropriate display macro
mmc: core: Add default timeout value for CMD6
mmc: sdhci-pci: add runtime pm support
...
Diffstat (limited to 'drivers/mmc/host/dw_mmc.c')
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 104 |
1 files changed, 78 insertions, 26 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index ff0f714b012..3aaeb084191 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -764,11 +764,29 @@ static int dw_mci_get_cd(struct mmc_host *mmc) return present; } +static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + u32 int_mask; + + /* Enable/disable Slot Specific SDIO interrupt */ + int_mask = mci_readl(host, INTMASK); + if (enb) { + mci_writel(host, INTMASK, + (int_mask | (1 << SDMMC_INT_SDIO(slot->id)))); + } else { + mci_writel(host, INTMASK, + (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id)))); + } +} + static const struct mmc_host_ops dw_mci_ops = { - .request = dw_mci_request, - .set_ios = dw_mci_set_ios, - .get_ro = dw_mci_get_ro, - .get_cd = dw_mci_get_cd, + .request = dw_mci_request, + .set_ios = dw_mci_set_ios, + .get_ro = dw_mci_get_ro, + .get_cd = dw_mci_get_cd, + .enable_sdio_irq = dw_mci_enable_sdio_irq, }; static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) @@ -1025,7 +1043,8 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 2) { - mci_writew(host, DATA, host->part_buf16); + mci_writew(host, DATA(host->data_offset), + host->part_buf16); host->part_buf_count = 0; } } @@ -1042,21 +1061,23 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writew(host, DATA, aligned_buf[i]); + mci_writew(host, DATA(host->data_offset), + aligned_buf[i]); } } else #endif { u16 *pdata = buf; for (; cnt >= 2; cnt -= 2) - mci_writew(host, DATA, *pdata++); + mci_writew(host, DATA(host->data_offset), *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writew(host, DATA, host->part_buf16); + mci_writew(host, DATA(host->data_offset), + host->part_buf16); } } @@ -1071,7 +1092,8 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) int items = len >> 1; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readw(host, DATA); + aligned_buf[i] = mci_readw(host, + DATA(host->data_offset)); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1082,11 +1104,11 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) { u16 *pdata = buf; for (; cnt >= 2; cnt -= 2) - *pdata++ = mci_readw(host, DATA); + *pdata++ = mci_readw(host, DATA(host->data_offset)); buf = pdata; } if (cnt) { - host->part_buf16 = mci_readw(host, DATA); + host->part_buf16 = mci_readw(host, DATA(host->data_offset)); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1099,7 +1121,8 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 4) { - mci_writel(host, DATA, host->part_buf32); + mci_writel(host, DATA(host->data_offset), + host->part_buf32); host->part_buf_count = 0; } } @@ -1116,21 +1139,23 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writel(host, DATA, aligned_buf[i]); + mci_writel(host, DATA(host->data_offset), + aligned_buf[i]); } } else #endif { u32 *pdata = buf; for (; cnt >= 4; cnt -= 4) - mci_writel(host, DATA, *pdata++); + mci_writel(host, DATA(host->data_offset), *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writel(host, DATA, host->part_buf32); + mci_writel(host, DATA(host->data_offset), + host->part_buf32); } } @@ -1145,7 +1170,8 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) int items = len >> 2; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readl(host, DATA); + aligned_buf[i] = mci_readl(host, + DATA(host->data_offset)); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1156,11 +1182,11 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) { u32 *pdata = buf; for (; cnt >= 4; cnt -= 4) - *pdata++ = mci_readl(host, DATA); + *pdata++ = mci_readl(host, DATA(host->data_offset)); buf = pdata; } if (cnt) { - host->part_buf32 = mci_readl(host, DATA); + host->part_buf32 = mci_readl(host, DATA(host->data_offset)); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1173,7 +1199,8 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 8) { - mci_writew(host, DATA, host->part_buf); + mci_writew(host, DATA(host->data_offset), + host->part_buf); host->part_buf_count = 0; } } @@ -1190,21 +1217,23 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writeq(host, DATA, aligned_buf[i]); + mci_writeq(host, DATA(host->data_offset), + aligned_buf[i]); } } else #endif { u64 *pdata = buf; for (; cnt >= 8; cnt -= 8) - mci_writeq(host, DATA, *pdata++); + mci_writeq(host, DATA(host->data_offset), *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writeq(host, DATA, host->part_buf); + mci_writeq(host, DATA(host->data_offset), + host->part_buf); } } @@ -1219,7 +1248,8 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) int items = len >> 3; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readq(host, DATA); + aligned_buf[i] = mci_readq(host, + DATA(host->data_offset)); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1230,11 +1260,11 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) { u64 *pdata = buf; for (; cnt >= 8; cnt -= 8) - *pdata++ = mci_readq(host, DATA); + *pdata++ = mci_readq(host, DATA(host->data_offset)); buf = pdata; } if (cnt) { - host->part_buf = mci_readq(host, DATA); + host->part_buf = mci_readq(host, DATA(host->data_offset)); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1406,6 +1436,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) struct dw_mci *host = dev_id; u32 status, pending; unsigned int pass_count = 0; + int i; do { status = mci_readl(host, RINTSTS); @@ -1477,6 +1508,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) queue_work(dw_mci_card_workqueue, &host->card_work); } + /* Handle SDIO Interrupts */ + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + if (pending & SDMMC_INT_SDIO(i)) { + mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); + mmc_signal_sdio_irq(slot->mmc); + } + } + } while (pass_count++ < 5); #ifdef CONFIG_MMC_DW_IDMAC @@ -1673,7 +1713,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); if (IS_ERR(host->vmmc)) { - printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); + pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; } else regulator_enable(host->vmmc); @@ -1924,6 +1964,18 @@ static int dw_mci_probe(struct platform_device *pdev) } /* + * In 2.40a spec, Data offset is changed. + * Need to check the version-id and set data-offset for DATA register. + */ + host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); + dev_info(&pdev->dev, "Version ID is %04x\n", host->verid); + + if (host->verid < DW_MMC_240A) + host->data_offset = DATA_OFFSET; + else + host->data_offset = DATA_240A_OFFSET; + + /* * Enable interrupts for command done, data over, data empty, card det, * receive ready and error such as transmit, receive timeout, crc error */ |