msm_sdcc.c revision 865c8064a2fb07100525097983966b8e789bde1a
19d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat/* 29d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver 39d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * 49d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Copyright (C) 2007 Google Inc, 59d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. 69d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * 79d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * This program is free software; you can redistribute it and/or modify 89d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * it under the terms of the GNU General Public License version 2 as 99d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * published by the Free Software Foundation. 109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * 119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Based on mmci.c 129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * 139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Author: San Mehat (san@android.com) 149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * 159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/module.h> 189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/moduleparam.h> 199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/init.h> 209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/ioport.h> 219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/device.h> 229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/interrupt.h> 239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/delay.h> 249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/err.h> 259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/highmem.h> 269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/log2.h> 279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/mmc/host.h> 289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/mmc/card.h> 29b3fa579118b239e218e690f5ef76870aff6fe738San Mehat#include <linux/mmc/sdio.h> 309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/clk.h> 319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/scatterlist.h> 329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/platform_device.h> 339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/dma-mapping.h> 349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/debugfs.h> 359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/io.h> 369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/memory.h> 379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/cacheflush.h> 399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/div64.h> 409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/sizes.h> 419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 423989d17847071fa94c93299805a9cca27cf65d26Pavel Machek#include <mach/mmc.h> 439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <mach/msm_iomap.h> 449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <mach/dma.h> 459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include "msm_sdcc.h" 479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define DRIVER_NAME "msm-sdcc" 499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_fmin = 144000; 519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_fmax = 50000000; 529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_4bit = 1; 539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_pwrsave = 1; 549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_piopoll = 1; 559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_sdioirq; 569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define PIO_SPINMAX 30 589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define CMD_SPINMAX 20 599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 60865c8064a2fb07100525097983966b8e789bde1aSan Mehat 61865c8064a2fb07100525097983966b8e789bde1aSan Mehatstatic inline int 62865c8064a2fb07100525097983966b8e789bde1aSan Mehatmsmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) 63865c8064a2fb07100525097983966b8e789bde1aSan Mehat{ 64865c8064a2fb07100525097983966b8e789bde1aSan Mehat int rc; 65865c8064a2fb07100525097983966b8e789bde1aSan Mehat WARN_ON(enable == host->clks_on); 66865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (enable) { 67865c8064a2fb07100525097983966b8e789bde1aSan Mehat rc = clk_enable(host->pclk); 68865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (rc) 69865c8064a2fb07100525097983966b8e789bde1aSan Mehat return rc; 70865c8064a2fb07100525097983966b8e789bde1aSan Mehat rc = clk_enable(host->clk); 71865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (rc) { 72865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->pclk); 73865c8064a2fb07100525097983966b8e789bde1aSan Mehat return rc; 74865c8064a2fb07100525097983966b8e789bde1aSan Mehat } 75865c8064a2fb07100525097983966b8e789bde1aSan Mehat udelay(30); 76865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->clks_on = 1; 77865c8064a2fb07100525097983966b8e789bde1aSan Mehat } else { 78865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->clk); 79865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->pclk); 80865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->clks_on = 0; 81865c8064a2fb07100525097983966b8e789bde1aSan Mehat } 82865c8064a2fb07100525097983966b8e789bde1aSan Mehat return 0; 83865c8064a2fb07100525097983966b8e789bde1aSan Mehat} 84865c8064a2fb07100525097983966b8e789bde1aSan Mehat 85865c8064a2fb07100525097983966b8e789bde1aSan Mehat 869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, 889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 c); 899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) 929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, host->base + MMCICOMMAND); 949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(host->curr.data); 969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data) 1019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = host->curr.data_xfered; 1029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->cmd->error == -ETIMEDOUT) 1039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mdelay(5); 1049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 105865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->use_bustimer) 106865c8064a2fb07100525097983966b8e789bde1aSan Mehat mod_timer(&host->busclk_timer, jiffies + HZ); 1079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 1089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Need to drop the host lock here; mmc_request_done may call 1099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * back into the driver... 1109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 1119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock(&host->lock); 1129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 1139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock(&host->lock); 1149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_stop_data(struct msmsdcc_host *host) 1189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, host->base + MMCIDATACTRL); 1209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data = NULL; 1219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_dataend = host->curr.got_datablkend = 0; 1229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatuint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) 1259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 12675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches switch (host->pdev_id) { 12775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 1: 1289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC1_PHYS + MMCIFIFO; 12975d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 2: 1309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC2_PHYS + MMCIFIFO; 13175d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 3: 1329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC3_PHYS + MMCIFIFO; 13375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 4: 1349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC4_PHYS + MMCIFIFO; 13575d145283b2e42619d7ee1e00b78466bacd51808Joe Perches } 13675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches BUG(); 1379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 1389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, 1429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int result, 1439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msm_dmov_errdata *err) 1449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_dma_data *dma_data = 1469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat container_of(cmd, struct msmsdcc_dma_data, hdr); 1479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dma_data->host; 1489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 1499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_request *mrq; 1509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 1529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq = host->curr.mrq; 1539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(!mrq); 1549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!(result & DMOV_RSLT_VALID)) { 1560a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("msmsdcc: Invalid DataMover result\n"); 1579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 1589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 1599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_DONE) { 1619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = host->curr.xfer_size; 1629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 1639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Error or flush */ 1649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_ERROR) 1650a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: DMA error (0x%.8x)\n", 1669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc), result); 1679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_FLUSH) 1680a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: DMA channel flushed (0x%.8x)\n", 1699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc), result); 1709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (err) 1710a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", 1729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat err->flush[0], err->flush[1], err->flush[2], 1739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat err->flush[3], err->flush[4], err->flush[5]); 1749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->error) 1759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->error = -EIO; 1769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 1779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.busy = 0; 1789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, 1799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir); 1809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.user_pages) { 1829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct scatterlist *sg = host->dma.sg; 1839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int i; 1849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 18575d145283b2e42619d7ee1e00b78466bacd51808Joe Perches for (i = 0; i < host->dma.num_ents; i++) 18675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches flush_dcache_page(sg_page(sg++)); 1879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 1889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 1909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((host->curr.got_dataend && host->curr.got_datablkend) 1929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat || mrq->data->error) { 1939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 1959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * If we've already gotten our DATAEND / DATABLKEND 1969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * for this request, then complete it through here. 1979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 1989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 1999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->error) 2019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = host->curr.xfer_size; 2029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->stop || mrq->cmd->error) { 2039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, host->base + MMCICOMMAND); 2049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 2059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 2069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = host->curr.data_xfered; 2079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 2099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 2109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 2119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 2129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_command(host, mrq->data->stop, 0); 2139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout: 2169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 2179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 2189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 2199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) 2219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 2229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.channel == -1) 2239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOENT; 2249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((data->blksz * data->blocks) < MCI_FIFOSIZE) 2269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 2279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((data->blksz * data->blocks) % MCI_FIFOSIZE) 2289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 2299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 2309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 2319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) 2339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 2349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_nc_dmadata *nc; 2359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dmov_box *box; 2369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t rows; 2379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t crci; 2389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int n; 2399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int i, rc; 2409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct scatterlist *sg = data->sg; 2419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = validate_dma(host, data); 2439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (rc) 2449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return rc; 2459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = data->sg; 2479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = data->sg_len; 2489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat nc = host->dma.nc; 2509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 25175d145283b2e42619d7ee1e00b78466bacd51808Joe Perches switch (host->pdev_id) { 25275d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 1: 2539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC1; 25475d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 25575d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 2: 2569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC2; 25775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 25875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 3: 2599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC3; 26075d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 26175d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 4: 2629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC4; 26375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 26475d145283b2e42619d7ee1e00b78466bacd51808Joe Perches default: 2659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 2669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = 0; 2679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOENT; 2689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) 2719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir = DMA_FROM_DEVICE; 2729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 2739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir = DMA_TO_DEVICE; 2749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.user_pages = 0; 2769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, 27875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches host->dma.num_ents, host->dma.dir); 2799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (n != host->dma.num_ents) { 2810a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unable to map in all sg elements\n", 2829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc)); 2839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 2849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = 0; 2859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOMEM; 2869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box = &nc->cmd[0]; 2899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat for (i = 0; i < host->dma.num_ents; i++) { 2909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd = CMD_MODE_BOX; 2919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (i == (host->dma.num_ents - 1)) 2939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_LC; 2949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? 2959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : 2969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (sg_dma_len(sg) / MCI_FIFOSIZE) ; 2979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) { 2999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_row_addr = msmsdcc_fifo_addr(host); 3009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->dst_row_addr = sg_dma_address(sg); 3019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_dst_len = (MCI_FIFOSIZE << 16) | 3039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_FIFOSIZE); 3049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->row_offset = MCI_FIFOSIZE; 3059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->num_rows = rows * ((1 << 16) + 1); 3079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_SRC_CRCI(crci); 3089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 3099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_row_addr = sg_dma_address(sg); 3109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->dst_row_addr = msmsdcc_fifo_addr(host); 3119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_dst_len = (MCI_FIFOSIZE << 16) | 3139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_FIFOSIZE); 3149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->row_offset = (MCI_FIFOSIZE << 16); 3159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->num_rows = rows * ((1 << 16) + 1); 3179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_DST_CRCI(crci); 3189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box++; 3209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat sg++; 3219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* location of command block must be 64 bit aligned */ 3249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(host->dma.cmd_busaddr & 0x07); 3259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; 3279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | 3289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); 3299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.hdr.complete_func = msmsdcc_dma_complete_func; 3305b00f40f90e7b17c11cf388680f43e8466b3666dSan Mehat host->dma.hdr.execute_func = NULL; 3319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 3339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 3349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 3369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) 3379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 3389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int datactrl, timeout; 3399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long long clks; 3409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 3419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int pio_irqmask = 0; 3429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data = data; 3449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_size = data->blksz * data->blocks; 3459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_remain = host->curr.xfer_size; 3469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = 0; 3479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_dataend = 0; 3489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_datablkend = 0; 3499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->pio, 0, sizeof(host->pio)); 3519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clks = (unsigned long long)data->timeout_ns * host->clk_rate; 35375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches do_div(clks, NSEC_PER_SEC); 3549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat timeout = data->timeout_clks + (unsigned int)clks; 3559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(timeout, base + MMCIDATATIMER); 3569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(host->curr.xfer_size, base + MMCIDATALENGTH); 3589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); 3609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!msmsdcc_config_dma(host, data)) 3629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl |= MCI_DPSM_DMAENABLE; 3639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else { 3649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg = data->sg; 3659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_len = data->sg_len; 3669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off = 0; 3679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) { 3699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask = MCI_RXFIFOHALFFULLMASK; 3709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.xfer_remain < MCI_FIFOSIZE) 3719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask |= MCI_RXDATAAVLBLMASK; 3729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 3739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask = MCI_TXFIFOHALFEMPTYMASK; 3749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) 3779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl |= MCI_DPSM_DIRECTION; 3789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(pio_irqmask, base + MMCIMASK1); 3809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(datactrl, base + MMCIDATACTRL); 3819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (datactrl & MCI_DPSM_DMAENABLE) { 3839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.busy = 1; 3849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); 3859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 3879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 388b3fa579118b239e218e690f5ef76870aff6fe738San Mehatstatic int 389b3fa579118b239e218e690f5ef76870aff6fe738San Mehatsnoop_cccr_abort(struct mmc_command *cmd) 390b3fa579118b239e218e690f5ef76870aff6fe738San Mehat{ 391b3fa579118b239e218e690f5ef76870aff6fe738San Mehat if ((cmd->opcode == 52) && 392b3fa579118b239e218e690f5ef76870aff6fe738San Mehat (cmd->arg & 0x80000000) && 393b3fa579118b239e218e690f5ef76870aff6fe738San Mehat (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) 394b3fa579118b239e218e690f5ef76870aff6fe738San Mehat return 1; 395b3fa579118b239e218e690f5ef76870aff6fe738San Mehat return 0; 396b3fa579118b239e218e690f5ef76870aff6fe738San Mehat} 397b3fa579118b239e218e690f5ef76870aff6fe738San Mehat 3989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 3999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) 4009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 4029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { 4049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, base + MMCICOMMAND); 4059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat udelay(2 + ((5 * 1000000) / host->clk_rate)); 4069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= cmd->opcode | MCI_CPSM_ENABLE; 4099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cmd->flags & MMC_RSP_PRESENT) { 4119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cmd->flags & MMC_RSP_136) 4129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CPSM_LONGRSP; 4139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CPSM_RESPONSE; 4149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 41675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches if (cmd->opcode == 17 || cmd->opcode == 18 || 41775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches cmd->opcode == 24 || cmd->opcode == 25 || 41875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches cmd->opcode == 53) 4199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CSPM_DATCMD; 4209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cmd == cmd->mrq->stop) 4229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CSPM_MCIABORT; 4239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 424b3fa579118b239e218e690f5ef76870aff6fe738San Mehat if (snoop_cccr_abort(cmd)) 425b3fa579118b239e218e690f5ef76870aff6fe738San Mehat c |= MCI_CSPM_MCIABORT; 426b3fa579118b239e218e690f5ef76870aff6fe738San Mehat 4279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = cmd; 4289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmds++; 4309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(cmd->arg, base + MMCIARGUMENT); 4329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(c, base + MMCICOMMAND); 4339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 4369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, 4379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int status) 4389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_DATACRCFAIL) { 4400a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc)); 4410a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: opcode 0x%.8x\n", __func__, 4429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->mrq->cmd->opcode); 4430a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: blksz %d, blocks %d\n", __func__, 4449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->blksz, data->blocks); 4459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EILSEQ; 4469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_DATATIMEOUT) { 4470a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Data timeout\n", mmc_hostname(host->mmc)); 4489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -ETIMEDOUT; 4499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_RXOVERRUN) { 4500a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: RX overrun\n", mmc_hostname(host->mmc)); 4519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 4529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_TXUNDERRUN) { 4530a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: TX underrun\n", mmc_hostname(host->mmc)); 4549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 4559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 4560a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unknown error (0x%.8x)\n", 4570a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), status); 4589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 4599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 4649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) 4659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 4679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t *ptr = (uint32_t *) buffer; 4689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int count = 0; 4699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat while (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) { 4719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat *ptr = readl(base + MMCIFIFO + (count % MCI_FIFOSIZE)); 4739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ptr++; 4749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat count += sizeof(uint32_t); 4759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= sizeof(uint32_t); 4779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) 4789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 4799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return count; 4819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 4849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, 4859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int remain, u32 status) 4869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 4889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat char *ptr = buffer; 4899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 4919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int count, maxcnt; 4929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : 4949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_FIFOHALFSIZE; 4959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat count = min(remain, maxcnt); 4969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writesl(base + MMCIFIFO, ptr, count >> 2); 4989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ptr += count; 4999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= count; 5009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) 5029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = readl(base + MMCISTATUS); 5059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (status & MCI_TXFIFOHALFEMPTY); 5069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return ptr - buffer; 5089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 5119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) 5129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat while (maxspin) { 5149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((readl(host->base + MMCISTATUS) & mask)) 5159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 5169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat udelay(1); 5179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat --maxspin; 5189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ETIMEDOUT; 5209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 5239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_irq(int irq, void *dev_id) 5249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 5269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 5279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t status; 5289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = readl(base + MMCISTATUS); 5309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 5329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 5339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int remain, len; 5349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat char *buffer; 5359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { 5379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) 5389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_spin_on_status(host, 5419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_TXFIFOHALFEMPTY | 5429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_RXDATAAVLBL), 5439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat PIO_SPINMAX)) { 5449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Map the current scatter buffer */ 5499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat local_irq_save(flags); 5509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat buffer = kmap_atomic(sg_page(host->pio.sg), 5519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat KM_BIO_SRC_IRQ) + host->pio.sg->offset; 5529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat buffer += host->pio.sg_off; 5539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain = host->pio.sg->length - host->pio.sg_off; 5549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = 0; 5559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE) 5569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = msmsdcc_pio_read(host, buffer, remain); 5579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_TXACTIVE) 5589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = msmsdcc_pio_write(host, buffer, remain, status); 5599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Unmap the buffer */ 5619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat kunmap_atomic(buffer, KM_BIO_SRC_IRQ); 5629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat local_irq_restore(flags); 5639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off += len; 5659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_remain -= len; 5669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered += len; 5679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= len; 5689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) { 5709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* This sg page is full - do some housekeeping */ 5719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE && host->curr.user_pages) 5729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat flush_dcache_page(sg_page(host->pio.sg)); 5739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!--host->pio.sg_len) { 5759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->pio, 0, sizeof(host->pio)); 5769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Advance to next sg */ 5809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg++; 5819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off = 0; 5829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = readl(base + MMCISTATUS); 5859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (1); 5869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) 5889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); 5899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->curr.xfer_remain) 5919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, base + MMCIMASK1); 5929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_HANDLED; 5949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) 5979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_command *cmd = host->curr.cmd; 5999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 6009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 6029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->resp[0] = readl(base + MMCIRESPONSE0); 6039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->resp[1] = readl(base + MMCIRESPONSE1); 6049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->resp[2] = readl(base + MMCIRESPONSE2); 6059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->resp[3] = readl(base + MMCIRESPONSE3); 6069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat del_timer(&host->command_timer); 6089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_CMDTIMEOUT) { 6099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->error = -ETIMEDOUT; 6109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_CMDCRCFAIL && 6119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->flags & MMC_RSP_CRC) { 6120a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); 6139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->error = -EILSEQ; 6149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!cmd->data || cmd->error) { 6179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.data && host->dma.sg) 6189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msm_dmov_stop_cmd(host->dma.channel, 6199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat &host->dma.hdr, 0); 6209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else if (host->curr.data) { /* Non DMA */ 6219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 6229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_request_end(host, cmd->mrq); 6239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else /* host->data == NULL */ 6249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_request_end(host, cmd->mrq); 6259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (!(cmd->data->flags & MMC_DATA_READ)) 6269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_data(host, cmd->data); 6279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 6289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 629b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesstatic void 630b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesmsmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, 631b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches void __iomem *base) 632b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches{ 633b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches struct mmc_data *data = host->curr.data; 634b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 635b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data) 636b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches return; 637b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 638b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* Check for data errors */ 639b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | 640b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches MCI_TXUNDERRUN | MCI_RXOVERRUN)) { 641b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_data_err(host, data, status); 642b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.data_xfered = 0; 643b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (host->dma.sg) 644b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msm_dmov_stop_cmd(host->dma.channel, 645b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches &host->dma.hdr, 0); 646b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else { 647b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_stop_data(host); 648b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->stop) 649b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_request_end(host, data->mrq); 650b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else 651b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_start_command(host, data->stop, 0); 652b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 653b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 654b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 655b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* Check for data done */ 656b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!host->curr.got_dataend && (status & MCI_DATAEND)) 657b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.got_dataend = 1; 658b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 659b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND)) 660b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.got_datablkend = 1; 661b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 662b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* 663b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * If DMA is still in progress, we complete via the completion handler 664b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches */ 665b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (host->curr.got_dataend && host->curr.got_datablkend && 666b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches !host->dma.busy) { 667b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* 668b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * There appears to be an issue in the controller where 669b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * if you request a small block transfer (< fifo size), 670b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * you may get your DATAEND/DATABLKEND irq without the 671b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * PIO data irq. 672b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * 673b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * Check to see if there is still data to be read, 674b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * and simulate a PIO irq. 675b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches */ 676b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) 677b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_pio_irq(1, host); 678b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 679b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_stop_data(host); 680b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->error) 681b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.data_xfered = host->curr.xfer_size; 682b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 683b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->stop) 684b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_request_end(host, data->mrq); 685b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else 686b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_start_command(host, data->stop, 0); 687b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 688b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches} 689b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 6909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t 6919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_irq(int irq, void *dev_id) 6929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 6939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 6949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 6959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 status; 6969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int ret = 0; 6979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int cardint = 0; 6989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock(&host->lock); 7009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 7029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = readl(base + MMCISTATUS); 7039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 704b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); 7059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(status, base + MMCICLEAR); 7069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 707865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (status & MCI_SDIOINTR) 708865c8064a2fb07100525097983966b8e789bde1aSan Mehat status &= ~MCI_SDIOINTR; 709865c8064a2fb07100525097983966b8e789bde1aSan Mehat 710865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!status) 711865c8064a2fb07100525097983966b8e789bde1aSan Mehat break; 712865c8064a2fb07100525097983966b8e789bde1aSan Mehat 713b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_handle_irq_data(host, status, base); 7149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | 7169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_CMDTIMEOUT) && host->curr.cmd) { 7179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_do_cmdirq(host, status); 7189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_SDIOINTOPER) { 7219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cardint = 1; 7229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status &= ~MCI_SDIOINTOPER; 7239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = 1; 7259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (status); 7269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock(&host->lock); 7289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 7309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * We have to delay handling the card interrupt as it calls 7319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * back into the driver. 7329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 7339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cardint) 7349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_signal_sdio_irq(host->mmc); 7359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_RETVAL(ret); 7379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 7389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 7409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) 7419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 7429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 7439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 7449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat WARN_ON(host->curr.mrq != NULL); 7469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat WARN_ON(host->pwr == 0); 7479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 7499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.reqs++; 7519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->eject) { 7539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) { 7549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = 0; 7559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = mrq->data->blksz * 7569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->blocks; 7579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 7589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = -ENOMEDIUM; 7599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 7619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(mmc, mrq); 7629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 7639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = mrq; 766865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!host->clks_on) 767865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 1); 7689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data && mrq->data->flags & MMC_DATA_READ) 7709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_data(host, mrq->data); 7719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_command(host, mrq->cmd, 0); 7739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->cmdpoll && !msmsdcc_spin_on_status(host, 7759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, 7769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat CMD_SPINMAX)) { 7779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t status = readl(host->base + MMCISTATUS); 7789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_do_cmdirq(host, status); 7799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, 7809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->base + MMCICLEAR); 7819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmdpoll_hits++; 7829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 7839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmdpoll_misses++; 7849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mod_timer(&host->command_timer, jiffies + HZ); 7859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 7879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 7889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 7909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 7919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 7929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 7939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 clk = 0, pwr = 0; 7949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int rc; 7954adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat unsigned long flags; 7969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7974adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat spin_lock_irqsave(&host->lock, flags); 798865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!host->clks_on) 799865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 1); 8009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 801865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (ios->clock) { 8029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->clock != host->clk_rate) { 8039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = clk_set_rate(host->clk, ios->clock); 8049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (rc < 0) 8050a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Error setting clock rate (%d)\n", 8060a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), rc); 8079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 8089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk_rate = ios->clock; 8099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= MCI_CLK_ENABLE; 8119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->bus_width == MMC_BUS_WIDTH_4) 8149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (2 << 10); /* Set WIDEBUS */ 8159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->clock > 400000 && msmsdcc_pwrsave) 8179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 9); /* PWRSAVE */ 8189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 12); /* FLOW_ENA */ 8209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 15); /* feedback clock */ 8219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->plat->translate_vdd) 8239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); 8249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat switch (ios->power_mode) { 8269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_OFF: 8279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 8289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_UP: 8299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_PWR_UP; 8309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 8319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_ON: 8329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_PWR_ON; 8339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 8349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 8379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_OD; 8389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(clk, host->base + MMCICLOCK); 8409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->pwr != pwr) { 8429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pwr = pwr; 8439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(pwr, host->base + MMCIPOWER); 8449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 845865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->clks_on) 8464adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 0); 8474adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat spin_unlock_irqrestore(&host->lock, flags); 8489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 8499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) 8519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 8529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 8539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 8549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 status; 8559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 8579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_sdioirq == 1) { 8589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = readl(host->base + MMCIMASK0); 8599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (enable) 8609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status |= MCI_SDIOINTOPERMASK; 8619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 8629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status &= ~MCI_SDIOINTOPERMASK; 8639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->saved_irq0mask = status; 8649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(status, host->base + MMCIMASK0); 8659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 8679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 8689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic const struct mmc_host_ops msmsdcc_ops = { 8709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .request = msmsdcc_request, 8719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .set_ios = msmsdcc_set_ios, 8729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .enable_sdio_irq = msmsdcc_enable_sdio_irq, 8739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}; 8749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 8769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_check_status(unsigned long data) 8779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 8789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = (struct msmsdcc_host *)data; 8799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int status; 8809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->plat->status) { 8829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, 0); 8839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 8849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = host->plat->status(mmc_dev(host->mmc)); 8879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->eject = !status; 8889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status ^ host->oldstat) { 8890a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Slot status change detected (%d -> %d)\n", 8900a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), host->oldstat, status); 8919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status) 8929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, (5 * HZ) / 2); 8939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 8949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, 0); 8959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->oldstat = status; 8989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout: 9009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->timer.function) 9019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mod_timer(&host->timer, jiffies + HZ); 9029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t 9059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_platform_status_irq(int irq, void *dev_id) 9069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 9089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_DEBUG "%s: %d\n", __func__, irq); 9109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_check_status((unsigned long) host); 9119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_HANDLED; 9129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 9159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_status_notify_cb(int card_present, void *dev_id) 9169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 9189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), 9209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat card_present); 9219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_check_status((unsigned long) host); 9229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 924865c8064a2fb07100525097983966b8e789bde1aSan Mehatstatic void 925865c8064a2fb07100525097983966b8e789bde1aSan Mehatmsmsdcc_busclk_expired(unsigned long _data) 926865c8064a2fb07100525097983966b8e789bde1aSan Mehat{ 927865c8064a2fb07100525097983966b8e789bde1aSan Mehat struct msmsdcc_host *host = (struct msmsdcc_host *) _data; 928865c8064a2fb07100525097983966b8e789bde1aSan Mehat unsigned long flags; 929865c8064a2fb07100525097983966b8e789bde1aSan Mehat 930865c8064a2fb07100525097983966b8e789bde1aSan Mehat spin_lock_irqsave(&host->lock, flags); 931865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->clks_on) 932865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 0); 933865c8064a2fb07100525097983966b8e789bde1aSan Mehat 934865c8064a2fb07100525097983966b8e789bde1aSan Mehat spin_unlock_irqrestore(&host->lock, flags); 935865c8064a2fb07100525097983966b8e789bde1aSan Mehat} 936865c8064a2fb07100525097983966b8e789bde1aSan Mehat 9379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat/* 9389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * called when a command expires. 9399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Dump some debugging, and then error 9409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * out the transaction. 9419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 9429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 9439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_command_expired(unsigned long _data) 9449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = (struct msmsdcc_host *) _data; 9469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_request *mrq; 9479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 9489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 9509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq = host->curr.mrq; 9519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq) { 9530a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Command expiry misfire\n", 9540a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc)); 9559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 9569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 9579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9590a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Command timeout (%p %p %p %p)\n", 9609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc), mrq, mrq->cmd, 9619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data, host->dma.sg); 9629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = -ETIMEDOUT; 9639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 9649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, host->base + MMCICOMMAND); 9669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 9689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 9699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 970865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->clks_on) 971865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 0); 9729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 9739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 9749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 9779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_init_dma(struct msmsdcc_host *host) 9789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data)); 9809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.host = host; 9819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.channel = -1; 9829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->dmares) 9849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENODEV; 9859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.nc = dma_alloc_coherent(NULL, 9879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat sizeof(struct msmsdcc_nc_dmadata), 9889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat &host->dma.nc_busaddr, 9899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat GFP_KERNEL); 9909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.nc == NULL) { 9910a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("Unable to allocate DMA buffer\n"); 9929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOMEM; 9939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata)); 9959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.cmd_busaddr = host->dma.nc_busaddr; 9969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.cmdptr_busaddr = host->dma.nc_busaddr + 9979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat offsetof(struct msmsdcc_nc_dmadata, cmdptr); 9989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.channel = host->dmares->start; 9999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 10019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ 10049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 10059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatdo_resume_work(struct work_struct *work) 10069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = 10089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat container_of(work, struct msmsdcc_host, resume_task); 10099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = host->mmc; 10109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 10129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_resume_host(mmc); 10139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 10149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat enable_irq(host->stat_irq); 10159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#endif 10189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 10209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_probe(struct platform_device *pdev) 10219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_platform_data *plat = pdev->dev.platform_data; 10239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host; 10249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc; 10259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *cmd_irqres = NULL; 10269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *pio_irqres = NULL; 10279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *stat_irqres = NULL; 10289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *memres = NULL; 10299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *dmares = NULL; 10309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int ret; 10319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* must have platform data */ 10339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!plat) { 10340a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Platform data not available\n", __func__); 10359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -EINVAL; 10369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 10379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (pdev->id < 1 || pdev->id > 4) 10409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 10419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (pdev->resource == NULL || pdev->num_resources < 2) { 10430a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Invalid resource\n", __func__); 10449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENXIO; 10459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); 10499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 10509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "cmd_irq"); 10519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 10529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "pio_irq"); 10539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 10549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "status_irq"); 10559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!cmd_irqres || !pio_irqres || !memres) { 10570a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Invalid resource\n", __func__); 10589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENXIO; 10599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 10629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup our host structure 10639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 10649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); 10669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mmc) { 10679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -ENOMEM; 10689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 10699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host = mmc_priv(mmc); 10729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pdev_id = pdev->id; 10739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->plat = plat; 10749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->mmc = mmc; 10759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->cmdpoll = 1; 10779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1078865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->use_bustimer = 1; 1079865c8064a2fb07100525097983966b8e789bde1aSan Mehat 10809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->base = ioremap(memres->start, PAGE_SIZE); 10819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->base) { 10829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -ENOMEM; 10839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 10849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->cmd_irqres = cmd_irqres; 10879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio_irqres = pio_irqres; 10889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->memres = memres; 10899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dmares = dmares; 10909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_init(&host->lock); 10919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 10939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup DMA 10949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 10959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_init_dma(host); 10969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10974adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat /* Get our clocks */ 10989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pclk = clk_get(&pdev->dev, "sdc_pclk"); 10999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (IS_ERR(host->pclk)) { 11009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = PTR_ERR(host->pclk); 11019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto host_free; 11029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk = clk_get(&pdev->dev, "sdc_clk"); 11059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (IS_ERR(host->clk)) { 11069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = PTR_ERR(host->clk); 11074adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat goto pclk_put; 11089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11104adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat /* Enable clocks */ 11114adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat ret = msmsdcc_enable_clocks(host, 1); 11129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 11139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_put; 11149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = clk_set_rate(host->clk, msmsdcc_fmin); 11169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) { 11170a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); 11189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_disable; 11199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11214adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat host->pclk_rate = clk_get_rate(host->pclk); 11229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk_rate = clk_get_rate(host->clk); 11239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup MMC host structure 11269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->ops = &msmsdcc_ops; 11289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->f_min = msmsdcc_fmin; 11299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->f_max = msmsdcc_fmax; 11309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->ocr_avail = plat->ocr_mask; 11319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_4bit) 11339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_4_BIT_DATA; 11349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_sdioirq) 11359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_SDIO_IRQ; 11369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; 11379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_phys_segs = NR_SG; 11399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_hw_segs = NR_SG; 11409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */ 11419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_blk_count = 65536; 11429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ 11449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_seg_size = mmc->max_req_size; 11459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, host->base + MMCIMASK0); 11479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0x5e007ff, host->base + MMCICLEAR); /* Add: 1 << 25 */ 11489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(MCI_IRQENABLE, host->base + MMCIMASK0); 11509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->saved_irq0mask = MCI_IRQENABLE; 11519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup card detect change 11549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->timer, 0, sizeof(host->timer)); 11579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) { 11599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long irqflags = IRQF_SHARED | 11609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (stat_irqres->flags & IRQF_TRIGGER_MASK); 11619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stat_irq = stat_irqres->start; 11639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(host->stat_irq, 11649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_platform_status_irq, 11659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat irqflags, 11669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (slot)", 11679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host); 11689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) { 11690a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unable to get slot IRQ %d (%d)\n", 11700a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->stat_irq, ret); 11719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_disable; 11729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (plat->register_status_notify) { 11749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat plat->register_status_notify(msmsdcc_status_notify_cb, host); 11759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (!plat->status) 11760a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: No card detect facilities available\n", 11779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(mmc)); 11789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else { 11799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat init_timer(&host->timer); 11809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.data = (unsigned long)host; 11819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.function = msmsdcc_check_status; 11829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.expires = jiffies + HZ; 11839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat add_timer(&host->timer); 11849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (plat->status) { 11879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->oldstat = host->plat->status(mmc_dev(host->mmc)); 11889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->eject = !host->oldstat; 11899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup a command timer. We currently need this due to 11939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * some 'strange' timeout / error handling situations. 11949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat init_timer(&host->command_timer); 11969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->command_timer.data = (unsigned long) host; 11979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->command_timer.function = msmsdcc_command_expired; 11989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1199865c8064a2fb07100525097983966b8e789bde1aSan Mehat init_timer(&host->busclk_timer); 1200865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->busclk_timer.data = (unsigned long) host; 1201865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->busclk_timer.function = msmsdcc_busclk_expired; 1202865c8064a2fb07100525097983966b8e789bde1aSan Mehat 12039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, 12049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (cmd)", host); 12059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 12069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto stat_irq_free; 12079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, 12099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (pio)", host); 12109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 12119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto cmd_irq_free; 12129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_set_drvdata(pdev, mmc); 12149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_add_host(mmc); 12159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12160a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", 12170a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), (unsigned long long)memres->start, 12180a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (unsigned int) cmd_irqres->start, 12190a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (unsigned int) host->stat_irq, host->dma.channel); 12200a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc), 12210a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); 12220a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", 12230a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); 12240a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); 12250a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Power save feature enable = %d\n", 12260a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), msmsdcc_pwrsave); 12279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.channel != -1) { 12290a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", 12300a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); 12310a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", 12320a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->dma.cmd_busaddr, 12330a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches host->dma.cmdptr_busaddr); 12349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 12350a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc)); 12369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->timer.function) 12370a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); 12389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 12409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd_irq_free: 12419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat free_irq(cmd_irqres->start, host); 12429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat stat_irq_free: 12439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 12449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat free_irq(host->stat_irq, host); 12459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_disable: 12464adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 0); 12479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put: 12489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put(host->clk); 12499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pclk_put: 12509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put(host->pclk); 12519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host_free: 12529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_free_host(mmc); 12539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat out: 12549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return ret; 12559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 12569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 12589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_suspend(struct platform_device *dev, pm_message_t state) 12599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 12609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = mmc_get_drvdata(dev); 12619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int rc = 0; 12629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 12649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 12659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 12679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat disable_irq(host->stat_irq); 12689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) 12709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = mmc_suspend_host(mmc, state); 12719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!rc) { 12729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(0, host->base + MMCIMASK0); 12739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12744adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat if (host->clks_on) 12754adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 0); 12769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 12779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 12789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return rc; 12799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 12809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 12829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_resume(struct platform_device *dev) 12839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 12849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = mmc_get_drvdata(dev); 12859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 12869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 12889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 12899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 12919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12924adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat if (!host->clks_on) 12934adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 1); 12949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writel(host->saved_irq0mask, host->base + MMCIMASK0); 12969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 12989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) 13009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_resume_host(mmc); 13015b8a2fb34f5670b1f07483bfa40de9ce539dbdb2Roel Kluin if (host->stat_irq) 13029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat enable_irq(host->stat_irq); 13039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 13049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 13059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic struct platform_driver msmsdcc_driver = { 13089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .probe = msmsdcc_probe, 13099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .suspend = msmsdcc_suspend, 13109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .resume = msmsdcc_resume, 13119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .driver = { 13129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .name = "msm_sdcc", 13139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat }, 13149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}; 13159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int __init msmsdcc_init(void) 13179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return platform_driver_register(&msmsdcc_driver); 13199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void __exit msmsdcc_exit(void) 13229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat platform_driver_unregister(&msmsdcc_driver); 13249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_init(msmsdcc_init); 13279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_exit(msmsdcc_exit); 13289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13299d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); 13309d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_LICENSE("GPL"); 1331