From patchwork Mon Mar 15 12:42:43 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: 86132 Received: from bear.ext.ti.com (bear.ext.ti.com [192.94.94.41]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2GChSKF032280 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 16 Mar 2010 12:44:06 GMT Received: from dlep34.itg.ti.com ([157.170.170.115]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id o2GChSRA007553 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 16 Mar 2010 07:43:28 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep34.itg.ti.com (8.13.7/8.13.7) with ESMTP id o2GChQpB025142 for ; Tue, 16 Mar 2010 07:43:27 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 14E658064A for ; Tue, 16 Mar 2010 06:43:26 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp51.itg.ti.com (dflp51.itg.ti.com [128.247.22.94]) by linux.omap.com (Postfix) with ESMTP id BD9E580626 for ; Tue, 16 Mar 2010 06:43:19 -0600 (CST) Received: from medina.ext.ti.com (localhost [127.0.0.1]) by dflp51.itg.ti.com (8.13.7/8.13.7) with ESMTP id o2GChJ23004826 for ; Tue, 16 Mar 2010 07:43:19 -0500 (CDT) Received: from psmtp.com (na3sys009amx173.postini.com [74.125.149.99]) by medina.ext.ti.com (8.13.7/8.13.7) with SMTP id o2GChFuK002292 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 16 Mar 2010 07:43:16 -0500 Received: from source ([122.165.19.237]) (using TLSv1) by na3sys009amx173.postini.com ([74.125.148.10]) with SMTP; Tue, 16 Mar 2010 12:43:16 GMT Received: from localhost.localdomain (alagu-xps [127.0.0.1]) by localhost.localdomain (8.14.2/8.14.2) with ESMTP id o2FCgibt023858; Mon, 15 Mar 2010 18:12:44 +0530 Received: (from alagu@localhost) by localhost.localdomain (8.14.2/8.14.2/Submit) id o2FCghtW023852; Mon, 15 Mar 2010 18:12:43 +0530 From: alagusankar@embwise.com To: davinci-linux-open-source@linux.davincidsp.com Subject: [PATCH] Davinci SDIO Support Date: Mon, 15 Mar 2010 18:12:43 +0530 Message-Id: <1268656963-23828-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]); Tue, 16 Mar 2010 12:44:06 +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);