From patchwork Mon Mar 15 12:59:36 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: alagusankar@embwise.com X-Patchwork-Id: 85936 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2FCxbrO018957 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 15 Mar 2010 13:00:13 GMT Received: from dlep36.itg.ti.com ([157.170.170.91]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id o2FCxbie020251 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 15 Mar 2010 07:59:37 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id o2FCxaNN000308 for ; Mon, 15 Mar 2010 07:59:37 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 049A880645 for ; Mon, 15 Mar 2010 06:59:36 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp52.itg.ti.com (dflp52.itg.ti.com [128.247.22.96]) by linux.omap.com (Postfix) with ESMTP id D61B080626 for ; Mon, 15 Mar 2010 06:59:29 -0600 (CST) Received: from neches.ext.ti.com (localhost [127.0.0.1]) by dflp52.itg.ti.com (8.13.7/8.13.7) with ESMTP id o2FCxTSc002880 for ; Mon, 15 Mar 2010 07:59:29 -0500 (CDT) Received: from psmtp.com (na3sys009amx239.postini.com [74.125.149.123]) by neches.ext.ti.com (8.13.7/8.13.7) with SMTP id o2FCxSIj007165 for ; Mon, 15 Mar 2010 07:59:29 -0500 Received: from source ([209.85.217.216]) by na3sys009amx239.postini.com ([74.125.148.10]) with SMTP; Mon, 15 Mar 2010 12:59:29 GMT Received: by gxk8 with SMTP id 8so1011757gxk.9 for ; Mon, 15 Mar 2010 05:59:28 -0700 (PDT) Received: by 10.101.159.2 with SMTP id l2mr1803041ano.142.1268657968064; Mon, 15 Mar 2010 05:59:28 -0700 (PDT) Received: from localhost.localdomain ([122.165.19.237]) by mx.google.com with ESMTPS id 20sm1644548ywh.48.2010.03.15.05.59.24 (version=TLSv1/SSLv3 cipher=RC4-MD5); Mon, 15 Mar 2010 05:59:26 -0700 (PDT) From: alagusankar@embwise.com To: davinci-linux-open-source@linux.davincidsp.com Subject: [PATCH] Davinci SDIO Support Date: Mon, 15 Mar 2010 18:29:36 +0530 Message-Id: <1268657976-24873-1-git-send-email-alagusankar@embwise.com> X-Mailer: git-send-email 1.6.0.6 X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:60.25650/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.5000) s cv gt3 gt2 gt1 r p m c X-pstn-addresses: from [db-null] X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 15 Mar 2010 13:00:14 +0000 (UTC) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 933cd42..2836ad1 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -66,8 +67,8 @@ #define DAVINCI_MMCBLNC 0x60 #define DAVINCI_SDIOCTL 0x64 #define DAVINCI_SDIOST0 0x68 -#define DAVINCI_SDIOEN 0x6C -#define DAVINCI_SDIOST 0x70 +#define DAVINCI_SDIOIEN 0x6C +#define DAVINCI_SDIOIST 0x70 #define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */ /* DAVINCI_MMCCTL definitions */ @@ -135,6 +136,23 @@ /* MMCSD Init clock in Hz in opendrain mode */ #define MMCSD_INIT_CLOCK 200000 +/* DAVINCI_SDIOCTL definitions */ +#define SDIOCTL_RDWTRQ_SET BIT(0) +#define SDIOCTL_RDWTCR_SET BIT(1) + +/* DAVINCI_SDIOST0 definitions */ +#define SDIOST0_DAT1_HI BIT(0) +#define SDIOST0_INTPRD BIT(1) +#define SDIOST0_RDWTST BIT(2) + +/* DAVINCI_SDIOIEN definitions */ +#define SDIOIEN_IOINTEN BIT(0) +#define SDIOIEN_RWSEN BIT(1) + +/* DAVINCI_SDIOIST definitions */ +#define SDIOIST_IOINT BIT(0) +#define SDIOIST_RWS BIT(1) + /* * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units, * and we handle up to NR_SG segments. MMC_BLOCK_BOUNCE kicks in only @@ -147,6 +165,8 @@ #define NR_SG 16 +#define DAVINCI_SDIO_IRQ(dev_id) (((dev_id) == 0) ? "sdio0" : "sdio1") + static unsigned rw_threshold = 32; module_param(rw_threshold, uint, S_IRUGO); MODULE_PARM_DESC(rw_threshold, @@ -164,7 +184,7 @@ struct mmc_davinci_host { unsigned int mmc_input_clk; void __iomem *base; struct resource *mem_res; - int irq; + int mmc_irq, sdio_irq; unsigned char bus_mode; #define DAVINCI_MMC_DATADIR_NONE 0 @@ -184,6 +204,7 @@ struct mmc_davinci_host { u32 rxdma, txdma; bool use_dma; bool do_dma; + bool sdio_int; /* Scatterlist DMA uses one or more parameter RAM entries: * the main one (associated with rxdma or txdma) plus zero or @@ -670,6 +691,24 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req) host->buffer = NULL; host->bytes_left = data->blocks * data->blksz; + /* + * Hack for overcoming the 2ms delay required by Libertas helper + * firmware download. Without this delay the primary firmware load fails + * without an error. Not having the delay does not result in host + * controller error (or) helper firmware download error. But will result + * in primary firmware load error. + * + * May not be required for usage with other SDIO client drivers and + * should be removed after identifying the root cause in consultation + * with the libertas developers. + */ + if (host->mmc->card) { + if (mmc_card_sdio(host->mmc->card)) { + if ((data->blksz == 64)) + mdelay(2); + } + } + /* For now we try to use DMA whenever we won't need partial FIFO * reads or writes, either for the whole transfer (as tested here) * or for any individual scatterlist segment (tested when we call @@ -862,6 +901,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) { host->data = NULL; + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { + /* SDIO Interrupt Detection work-around as suggested by + * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata + * 2.1.5) + * Signal SDIO interrupt only if it is enabled by core + */ + if (host->sdio_int && (!((readl(host->base + DAVINCI_SDIOST0)) + & SDIOST0_DAT1_HI))) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + } + if (host->do_dma) { davinci_abort_dma(host); @@ -928,6 +980,22 @@ davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) mmc_davinci_reset_ctrl(host, 0); } +static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) +{ + struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; + unsigned int status; + + status = readl(host->base + DAVINCI_SDIOIST); + if (status & SDIOIST_IOINT) { + dev_dbg(mmc_dev(host->mmc), + "SDIO interrupt status %x\n", status); + writel(status | SDIOIST_IOINT, + host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + return IRQ_HANDLED; +} + static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) { struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; @@ -1072,11 +1140,33 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc) return config->get_ro(pdev->id); } +static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct mmc_davinci_host *host = mmc_priv(mmc); + + if (enable) { + if (!((readl(host->base + DAVINCI_SDIOST0)) + & SDIOST0_DAT1_HI)) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } else { + host->sdio_int = 1; + writel(readl(host->base + DAVINCI_SDIOIEN) | + SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); + } + } else { + host->sdio_int = 0; + writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN, + host->base + DAVINCI_SDIOIEN); + } + +} static struct mmc_host_ops mmc_davinci_ops = { - .request = mmc_davinci_request, - .set_ios = mmc_davinci_set_ios, - .get_cd = mmc_davinci_get_cd, - .get_ro = mmc_davinci_get_ro, + .request = mmc_davinci_request, + .set_ios = mmc_davinci_set_ios, + .get_cd = mmc_davinci_get_cd, + .get_ro = mmc_davinci_get_ro, + .enable_sdio_irq = mmc_davinci_enable_sdio_irq, }; /*----------------------------------------------------------------------*/ @@ -1199,7 +1289,8 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) init_mmcsd_host(host); host->use_dma = use_dma; - host->irq = irq; + host->mmc_irq = irq; + host->sdio_irq = platform_get_irq(pdev, 1); if (host->use_dma && davinci_acquire_dma_channels(host) != 0) host->use_dma = 0; @@ -1258,10 +1349,24 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) if (ret < 0) goto out; - ret = request_irq(irq, mmc_davinci_irq, 0, mmc_hostname(mmc), host); + ret = request_irq(host->mmc_irq, mmc_davinci_irq, 0, + mmc_hostname(mmc), host); if (ret) goto out; + /* Failures in SDIO IRQ registration are ignored as the driver + * can still work in polled mode. + */ + if (host->sdio_irq != NO_IRQ) { + ret = request_irq(host->sdio_irq, + mmc_davinci_sdio_irq, 0, + DAVINCI_SDIO_IRQ(pdev->id), host); + if (ret == 0) { + mmc->caps |= MMC_CAP_SDIO_IRQ; + host->sdio_int = 0; + } + } + rename_region(mem, mmc_hostname(mmc)); dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", @@ -1305,9 +1410,13 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) mmc_davinci_cpufreq_deregister(host); mmc_remove_host(host->mmc); - free_irq(host->irq, host); + free_irq(host->mmc_irq, host); - davinci_release_dma_channels(host); + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) + free_irq(host->sdio_irq, host); + + if (host->use_dma) + davinci_release_dma_channels(host); clk_disable(host->clk); clk_put(host->clk);