From 2971944582ff43b7dedbb460777052243ac9915a Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:54:43 +0100 Subject: ARM: 6307/1: mmci: allow the card detect GPIO value not to be inverted On some platforms, the GPIO value from the gpio_cd pin doesn't need to be inverted to get it active high. Add a cd_invert platform data parameter and change existing platforms using GPIO for CD (only Realview) to enable it. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 840b301b5671..9a9aeac50a6c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -570,12 +570,13 @@ static int mmci_get_ro(struct mmc_host *mmc) static int mmci_get_cd(struct mmc_host *mmc) { struct mmci_host *host = mmc_priv(mmc); + struct mmci_platform_data *plat = host->plat; unsigned int status; if (host->gpio_cd == -ENOSYS) - status = host->plat->status(mmc_dev(host->mmc)); + status = plat->status(mmc_dev(host->mmc)); else - status = !gpio_get_value(host->gpio_cd); + status = !!gpio_get_value(host->gpio_cd) ^ plat->cd_invert; /* * Use positive logic throughout - status is zero for no card, -- cgit v1.2.3 From 8301bb68c6bb9836889641a47443aeb97b763f6c Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:57:30 +0100 Subject: ARM: 6310/1: mmci: support different FIFO sizes The Ux500 variant has a 32-word FIFO (TXFIFOEMPTY is asserted when it has 2 left) and TXFIFOHALFEMPTY is repurposed as TXFIFOBURSTWRITEABLE, with a burst being defined as 8-words. Likewise for RX. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 22 +++++++++++++++++++--- drivers/mmc/host/mmci.h | 7 ------- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 9a9aeac50a6c..1932e9cc8f52 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -41,23 +41,35 @@ static unsigned int fmax = 515633; * @clkreg: default value for MCICLOCK register * @clkreg_enable: enable value for MMCICLOCK register * @datalength_bits: number of bits in the MMCIDATALENGTH register + * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY + * is asserted (likewise for RX) + * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY + * is asserted (likewise for RX) */ struct variant_data { unsigned int clkreg; unsigned int clkreg_enable; unsigned int datalength_bits; + unsigned int fifosize; + unsigned int fifohalfsize; }; static struct variant_data variant_arm = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, .datalength_bits = 16, }; static struct variant_data variant_u300 = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, }; static struct variant_data variant_ux500 = { + .fifosize = 30 * 4, + .fifohalfsize = 8 * 4, .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, @@ -138,6 +150,7 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { + struct variant_data *variant = host->variant; unsigned int datactrl, timeout, irqmask; unsigned long long clks; void __iomem *base; @@ -173,7 +186,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) * If we have less than a FIFOSIZE of bytes to transfer, * trigger a PIO interrupt as soon as any data is available. */ - if (host->size < MCI_FIFOSIZE) + if (host->size < variant->fifosize) irqmask |= MCI_RXDATAAVLBLMASK; } else { /* @@ -332,13 +345,15 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) { + struct variant_data *variant = host->variant; void __iomem *base = host->base; char *ptr = buffer; do { unsigned int count, maxcnt; - maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; + maxcnt = status & MCI_TXFIFOEMPTY ? + variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); writesl(base + MMCIFIFO, ptr, count >> 2); @@ -362,6 +377,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) { struct mmci_host *host = dev_id; struct sg_mapping_iter *sg_miter = &host->sg_miter; + struct variant_data *variant = host->variant; void __iomem *base = host->base; unsigned long flags; u32 status; @@ -420,7 +436,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * If we're nearing the end of the read, switch to * "any data available" mode. */ - if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) + if (status & MCI_RXACTIVE && host->size < variant->fifosize) writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); /* diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 68970cfb81e1..4e18f5403f48 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -133,13 +133,6 @@ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) -/* - * The size of the FIFO in bytes. - */ -#define MCI_FIFOSIZE (16*4) - -#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) - #define NR_SG 16 struct clk; -- cgit v1.2.3 From 148b8b39c156424da22693d26adcb69800faf95e Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:55:48 +0100 Subject: ARM: 6308/1: mmci: support card detection interrupts If an IRQ can be requested on the card detected GPIO, use it instead of polling. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 24 +++++++++++++++++++++++- drivers/mmc/host/mmci.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 1932e9cc8f52..a922a0028836 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -601,6 +601,15 @@ static int mmci_get_cd(struct mmc_host *mmc) return status; } +static irqreturn_t mmci_cd_irq(int irq, void *dev_id) +{ + struct mmci_host *host = dev_id; + + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + + return IRQ_HANDLED; +} + static const struct mmc_host_ops mmci_ops = { .request = mmci_request, .set_ios = mmci_set_ios, @@ -637,6 +646,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host->gpio_wp = -ENOSYS; host->gpio_cd = -ENOSYS; + host->gpio_cd_irq = -1; host->hw_designer = amba_manf(dev); host->hw_revision = amba_rev(dev); @@ -716,7 +726,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (host->vcc == NULL) mmc->ocr_avail = plat->ocr_mask; mmc->caps = plat->capabilities; - mmc->caps |= MMC_CAP_NEEDS_POLL; /* * We can do SGIO @@ -761,6 +770,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host->gpio_cd = plat->gpio_cd; else if (ret != -ENOSYS) goto err_gpio_cd; + + ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), + mmci_cd_irq, 0, + DRIVER_NAME " (cd)", host); + if (ret >= 0) + host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } if (gpio_is_valid(plat->gpio_wp)) { ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); @@ -772,6 +787,9 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto err_gpio_wp; } + if (host->gpio_cd_irq < 0) + mmc->caps |= MMC_CAP_NEEDS_POLL; + ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto unmap; @@ -798,6 +816,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); err_gpio_wp: + if (host->gpio_cd_irq >= 0) + free_irq(host->gpio_cd_irq, host); if (host->gpio_cd != -ENOSYS) gpio_free(host->gpio_cd); err_gpio_cd: @@ -836,6 +856,8 @@ static int __devexit mmci_remove(struct amba_device *dev) if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); + if (host->gpio_cd_irq >= 0) + free_irq(host->gpio_cd_irq, host); if (host->gpio_cd != -ENOSYS) gpio_free(host->gpio_cd); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 4e18f5403f48..c7d373c7aec9 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -147,6 +147,7 @@ struct mmci_host { struct clk *clk; int gpio_cd; int gpio_wp; + int gpio_cd_irq; unsigned int data_xfered; -- cgit v1.2.3 From 4b8caec09562ce7e6e3aaf2954eef8ea73ba67b8 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 9 Aug 2010 12:56:40 +0100 Subject: ARM: 6309/1: mmci: allow neither ->status nor gpio_cd to be specified The card may be always present on the board, and for these cases neither a status callback nor a card detect GPIO is required, and card detection polling can be disabled. Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index a922a0028836..fd89d9230928 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -589,9 +589,12 @@ static int mmci_get_cd(struct mmc_host *mmc) struct mmci_platform_data *plat = host->plat; unsigned int status; - if (host->gpio_cd == -ENOSYS) + if (host->gpio_cd == -ENOSYS) { + if (!plat->status) + return 1; /* Assume always present */ + status = plat->status(mmc_dev(host->mmc)); - else + } else status = !!gpio_get_value(host->gpio_cd) ^ plat->cd_invert; /* @@ -787,7 +790,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto err_gpio_wp; } - if (host->gpio_cd_irq < 0) + if ((host->plat->status || host->gpio_cd != -ENOSYS) + && host->gpio_cd_irq < 0) mmc->caps |= MMC_CAP_NEEDS_POLL; ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); -- cgit v1.2.3 From 18a06301158b5e4e9fae29e477f468e23f3eda90 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 12 Sep 2010 12:56:44 +0100 Subject: ARM: 6370/1: mmci: use _cansleep GPIO functions Currently the kernel is screaming about slowpath at me for the wp/cd callbacks. Switch to the _cansleep variants so as to silence this. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fd89d9230928..f2e02d7d9f3d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -580,7 +580,7 @@ static int mmci_get_ro(struct mmc_host *mmc) if (host->gpio_wp == -ENOSYS) return -ENOSYS; - return gpio_get_value(host->gpio_wp); + return gpio_get_value_cansleep(host->gpio_wp); } static int mmci_get_cd(struct mmc_host *mmc) @@ -595,7 +595,8 @@ static int mmci_get_cd(struct mmc_host *mmc) status = plat->status(mmc_dev(host->mmc)); } else - status = !!gpio_get_value(host->gpio_cd) ^ plat->cd_invert; + status = !!gpio_get_value_cansleep(host->gpio_cd) + ^ plat->cd_invert; /* * Use positive logic throughout - status is zero for no card, -- cgit v1.2.3 From 725343fa748fc9b7c883d198e9cec391425aa478 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 9 Oct 2010 13:43:21 +0100 Subject: ARM: 6437/2: mmci: add some register defines for ST Micro variants This adds a few registers to the MMCI/PL180 derivates that is used for some odd control stuff like SDIO. Signed-off-by: Marcin Mielczarczyk Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index c7d373c7aec9..4ae887fc0189 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -54,10 +54,16 @@ #define MCI_DPSM_MODE (1 << 2) #define MCI_DPSM_DMAENABLE (1 << 3) #define MCI_DPSM_BLOCKSIZE (1 << 4) -#define MCI_DPSM_RWSTART (1 << 8) -#define MCI_DPSM_RWSTOP (1 << 9) -#define MCI_DPSM_RWMOD (1 << 10) -#define MCI_DPSM_SDIOEN (1 << 11) +/* Control register extensions in the ST Micro U300 and Ux500 versions */ +#define MCI_ST_DPSM_RWSTART (1 << 8) +#define MCI_ST_DPSM_RWSTOP (1 << 9) +#define MCI_ST_DPSM_RWMOD (1 << 10) +#define MCI_ST_DPSM_SDIOEN (1 << 11) +/* Control register extensions in the ST Micro Ux500 versions */ +#define MCI_ST_DPSM_DMAREQCTL (1 << 12) +#define MCI_ST_DPSM_DBOOTMODEEN (1 << 13) +#define MCI_ST_DPSM_BUSYMODE (1 << 14) +#define MCI_ST_DPSM_DDRMODE (1 << 15) #define MMCIDATACNT 0x030 #define MMCISTATUS 0x034 -- cgit v1.2.3