msm_sdcc.c revision 8b1c2ba274c8416afb7eab3bd788f98a917efe06
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; 658b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat 66865c8064a2fb07100525097983966b8e789bde1aSan Mehat WARN_ON(enable == host->clks_on); 67865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (enable) { 68865c8064a2fb07100525097983966b8e789bde1aSan Mehat rc = clk_enable(host->pclk); 69865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (rc) 70865c8064a2fb07100525097983966b8e789bde1aSan Mehat return rc; 71865c8064a2fb07100525097983966b8e789bde1aSan Mehat rc = clk_enable(host->clk); 72865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (rc) { 73865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->pclk); 74865c8064a2fb07100525097983966b8e789bde1aSan Mehat return rc; 75865c8064a2fb07100525097983966b8e789bde1aSan Mehat } 768b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat udelay(1 + ((3 * USEC_PER_SEC) / 778b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); 78865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->clks_on = 1; 79865c8064a2fb07100525097983966b8e789bde1aSan Mehat } else { 80865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->clk); 81865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->pclk); 82865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->clks_on = 0; 83865c8064a2fb07100525097983966b8e789bde1aSan Mehat } 84865c8064a2fb07100525097983966b8e789bde1aSan Mehat return 0; 85865c8064a2fb07100525097983966b8e789bde1aSan Mehat} 86865c8064a2fb07100525097983966b8e789bde1aSan Mehat 878b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatstatic inline unsigned int 888b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatmsmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) 898b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat{ 908b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat return readl(host->base + reg); 918b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat} 928b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat 938b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatstatic inline void 948b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatmsmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) 958b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat{ 968b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat writel(data, host->base + reg); 978b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat /* 3 clk delay required! */ 988b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat udelay(1 + ((3 * USEC_PER_SEC) / 998b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); 1008b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat} 101865c8064a2fb07100525097983966b8e789bde1aSan Mehat 1029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, 1049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 c); 1059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) 1089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1098b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCICOMMAND); 1109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(host->curr.data); 1129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 1149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 1159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data) 1179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = host->curr.data_xfered; 1189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->cmd->error == -ETIMEDOUT) 1199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mdelay(5); 1209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 121865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->use_bustimer) 122865c8064a2fb07100525097983966b8e789bde1aSan Mehat mod_timer(&host->busclk_timer, jiffies + HZ); 1239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 1249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Need to drop the host lock here; mmc_request_done may call 1259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * back into the driver... 1269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 1279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock(&host->lock); 1289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 1299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock(&host->lock); 1309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_stop_data(struct msmsdcc_host *host) 1349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1358b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCIDATACTRL); 1369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data = NULL; 1379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_dataend = host->curr.got_datablkend = 0; 1389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatuint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) 1419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 14275d145283b2e42619d7ee1e00b78466bacd51808Joe Perches switch (host->pdev_id) { 14375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 1: 1449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC1_PHYS + MMCIFIFO; 14575d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 2: 1469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC2_PHYS + MMCIFIFO; 14775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 3: 1489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC3_PHYS + MMCIFIFO; 14975d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 4: 1509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC4_PHYS + MMCIFIFO; 15175d145283b2e42619d7ee1e00b78466bacd51808Joe Perches } 15275d145283b2e42619d7ee1e00b78466bacd51808Joe Perches BUG(); 1539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 1549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, 1589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int result, 1599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msm_dmov_errdata *err) 1609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_dma_data *dma_data = 1629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat container_of(cmd, struct msmsdcc_dma_data, hdr); 1639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dma_data->host; 1649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 1659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_request *mrq; 1669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 1689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq = host->curr.mrq; 1699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(!mrq); 1709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!(result & DMOV_RSLT_VALID)) { 1720a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("msmsdcc: Invalid DataMover result\n"); 1739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 1749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 1759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_DONE) { 1779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = host->curr.xfer_size; 1789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 1799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Error or flush */ 1809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_ERROR) 1810a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: DMA error (0x%.8x)\n", 1829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc), result); 1839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_FLUSH) 1840a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: DMA channel flushed (0x%.8x)\n", 1859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc), result); 1869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (err) 1870a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", 1889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat err->flush[0], err->flush[1], err->flush[2], 1899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat err->flush[3], err->flush[4], err->flush[5]); 1909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->error) 1919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->error = -EIO; 1929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 1939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.busy = 0; 1949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, 1959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir); 1969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.user_pages) { 1989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct scatterlist *sg = host->dma.sg; 1999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int i; 2009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 20175d145283b2e42619d7ee1e00b78466bacd51808Joe Perches for (i = 0; i < host->dma.num_ents; i++) 20275d145283b2e42619d7ee1e00b78466bacd51808Joe Perches flush_dcache_page(sg_page(sg++)); 2039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 2069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((host->curr.got_dataend && host->curr.got_datablkend) 2089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat || mrq->data->error) { 2099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 2119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * If we've already gotten our DATAEND / DATABLKEND 2129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * for this request, then complete it through here. 2139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 2149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 2159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->error) 2179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = host->curr.xfer_size; 2189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->stop || mrq->cmd->error) { 2198b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCICOMMAND); 2209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 2219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 2229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = host->curr.data_xfered; 2239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 2259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 2269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 2279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 2289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_command(host, mrq->data->stop, 0); 2299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout: 2329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 2339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 2349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 2359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) 2379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 2389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.channel == -1) 2399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOENT; 2409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((data->blksz * data->blocks) < MCI_FIFOSIZE) 2429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 2439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((data->blksz * data->blocks) % MCI_FIFOSIZE) 2449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 2459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 2469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 2479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) 2499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 2509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_nc_dmadata *nc; 2519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dmov_box *box; 2529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t rows; 2539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t crci; 2549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int n; 2559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int i, rc; 2569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct scatterlist *sg = data->sg; 2579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = validate_dma(host, data); 2599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (rc) 2609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return rc; 2619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = data->sg; 2639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = data->sg_len; 2649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat nc = host->dma.nc; 2669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 26775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches switch (host->pdev_id) { 26875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 1: 2699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC1; 27075d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 27175d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 2: 2729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC2; 27375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 27475d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 3: 2759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC3; 27675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 27775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 4: 2789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC4; 27975d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 28075d145283b2e42619d7ee1e00b78466bacd51808Joe Perches default: 2819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 2829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = 0; 2839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOENT; 2849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) 2879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir = DMA_FROM_DEVICE; 2889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 2899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir = DMA_TO_DEVICE; 2909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.user_pages = 0; 2929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, 29475d145283b2e42619d7ee1e00b78466bacd51808Joe Perches host->dma.num_ents, host->dma.dir); 2959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (n != host->dma.num_ents) { 2970a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unable to map in all sg elements\n", 2989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc)); 2999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 3009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = 0; 3019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOMEM; 3029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box = &nc->cmd[0]; 3059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat for (i = 0; i < host->dma.num_ents; i++) { 3069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd = CMD_MODE_BOX; 3079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (i == (host->dma.num_ents - 1)) 3099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_LC; 3109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? 3119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : 3129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (sg_dma_len(sg) / MCI_FIFOSIZE) ; 3139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) { 3159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_row_addr = msmsdcc_fifo_addr(host); 3169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->dst_row_addr = sg_dma_address(sg); 3179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_dst_len = (MCI_FIFOSIZE << 16) | 3199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_FIFOSIZE); 3209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->row_offset = MCI_FIFOSIZE; 3219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->num_rows = rows * ((1 << 16) + 1); 3239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_SRC_CRCI(crci); 3249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 3259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_row_addr = sg_dma_address(sg); 3269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->dst_row_addr = msmsdcc_fifo_addr(host); 3279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_dst_len = (MCI_FIFOSIZE << 16) | 3299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_FIFOSIZE); 3309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->row_offset = (MCI_FIFOSIZE << 16); 3319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->num_rows = rows * ((1 << 16) + 1); 3339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_DST_CRCI(crci); 3349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box++; 3369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat sg++; 3379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* location of command block must be 64 bit aligned */ 3409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(host->dma.cmd_busaddr & 0x07); 3419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; 3439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | 3449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); 3459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.hdr.complete_func = msmsdcc_dma_complete_func; 3465b00f40f90e7b17c11cf388680f43e8466b3666dSan Mehat host->dma.hdr.execute_func = NULL; 3479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 3499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 3509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 3529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) 3539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 3549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int datactrl, timeout; 3559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long long clks; 3569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int pio_irqmask = 0; 3579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data = data; 3599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_size = data->blksz * data->blocks; 3609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_remain = host->curr.xfer_size; 3619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = 0; 3629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_dataend = 0; 3639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_datablkend = 0; 3649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->pio, 0, sizeof(host->pio)); 3669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clks = (unsigned long long)data->timeout_ns * host->clk_rate; 36875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches do_div(clks, NSEC_PER_SEC); 3699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat timeout = data->timeout_clks + (unsigned int)clks; 3708b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, timeout, MMCIDATATIMER); 3719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3728b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); 3739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); 3759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!msmsdcc_config_dma(host, data)) 3779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl |= MCI_DPSM_DMAENABLE; 3789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else { 3799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg = data->sg; 3809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_len = data->sg_len; 3819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off = 0; 3829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) { 3849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask = MCI_RXFIFOHALFFULLMASK; 3859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.xfer_remain < MCI_FIFOSIZE) 3869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask |= MCI_RXDATAAVLBLMASK; 3879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 3889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask = MCI_TXFIFOHALFEMPTYMASK; 3899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) 3929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl |= MCI_DPSM_DIRECTION; 3939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3948b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, pio_irqmask, MMCIMASK1); 3958b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, datactrl, MMCIDATACTRL); 3969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (datactrl & MCI_DPSM_DMAENABLE) { 3989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.busy = 1; 3999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); 4009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 403b3fa579118b239e218e690f5ef76870aff6fe738San Mehatstatic int 404b3fa579118b239e218e690f5ef76870aff6fe738San Mehatsnoop_cccr_abort(struct mmc_command *cmd) 405b3fa579118b239e218e690f5ef76870aff6fe738San Mehat{ 406b3fa579118b239e218e690f5ef76870aff6fe738San Mehat if ((cmd->opcode == 52) && 407b3fa579118b239e218e690f5ef76870aff6fe738San Mehat (cmd->arg & 0x80000000) && 408b3fa579118b239e218e690f5ef76870aff6fe738San Mehat (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) 409b3fa579118b239e218e690f5ef76870aff6fe738San Mehat return 1; 410b3fa579118b239e218e690f5ef76870aff6fe738San Mehat return 0; 411b3fa579118b239e218e690f5ef76870aff6fe738San Mehat} 412b3fa579118b239e218e690f5ef76870aff6fe738San Mehat 4139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 4149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) 4159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4168b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat if (msmsdcc_readl(host, MMCICOMMAND) & MCI_CPSM_ENABLE) 4178b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCICOMMAND); 4189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= cmd->opcode | MCI_CPSM_ENABLE; 4209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cmd->flags & MMC_RSP_PRESENT) { 4229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cmd->flags & MMC_RSP_136) 4239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CPSM_LONGRSP; 4249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CPSM_RESPONSE; 4259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 42775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches if (cmd->opcode == 17 || cmd->opcode == 18 || 42875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches cmd->opcode == 24 || cmd->opcode == 25 || 42975d145283b2e42619d7ee1e00b78466bacd51808Joe Perches cmd->opcode == 53) 4309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CSPM_DATCMD; 4319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cmd == cmd->mrq->stop) 4339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CSPM_MCIABORT; 4349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 435b3fa579118b239e218e690f5ef76870aff6fe738San Mehat if (snoop_cccr_abort(cmd)) 436b3fa579118b239e218e690f5ef76870aff6fe738San Mehat c |= MCI_CSPM_MCIABORT; 437b3fa579118b239e218e690f5ef76870aff6fe738San Mehat 4389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = cmd; 4399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmds++; 4419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4428b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, cmd->arg, MMCIARGUMENT); 4438b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, c, MMCICOMMAND); 4449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 4479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, 4489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int status) 4499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_DATACRCFAIL) { 4510a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc)); 4520a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: opcode 0x%.8x\n", __func__, 4539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->mrq->cmd->opcode); 4540a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: blksz %d, blocks %d\n", __func__, 4559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->blksz, data->blocks); 4569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EILSEQ; 4579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_DATATIMEOUT) { 4580a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Data timeout\n", mmc_hostname(host->mmc)); 4599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -ETIMEDOUT; 4609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_RXOVERRUN) { 4610a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: RX overrun\n", mmc_hostname(host->mmc)); 4629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 4639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_TXUNDERRUN) { 4640a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: TX underrun\n", mmc_hostname(host->mmc)); 4659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 4669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 4670a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unknown error (0x%.8x)\n", 4680a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), status); 4699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 4709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 4759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) 4769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t *ptr = (uint32_t *) buffer; 4789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int count = 0; 4799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4808b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { 4818b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); 4829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ptr++; 4839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat count += sizeof(uint32_t); 4849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= sizeof(uint32_t); 4869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) 4879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 4889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return count; 4909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 4939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, 4949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int remain, u32 status) 4959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 4979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat char *ptr = buffer; 4989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 5009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int count, maxcnt; 5019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : 5039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_FIFOHALFSIZE; 5049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat count = min(remain, maxcnt); 5059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writesl(base + MMCIFIFO, ptr, count >> 2); 5079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ptr += count; 5089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= count; 5099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) 5119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5138b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 5149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (status & MCI_TXFIFOHALFEMPTY); 5159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return ptr - buffer; 5179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 5209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) 5219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat while (maxspin) { 5238b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat if ((msmsdcc_readl(host, MMCISTATUS) & mask)) 5249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 5259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat udelay(1); 5269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat --maxspin; 5279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ETIMEDOUT; 5299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 5329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_irq(int irq, void *dev_id) 5339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 5359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t status; 5369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5378b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 5389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 5409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 5419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int remain, len; 5429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat char *buffer; 5439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { 5459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) 5469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_spin_on_status(host, 5499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_TXFIFOHALFEMPTY | 5509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_RXDATAAVLBL), 5519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat PIO_SPINMAX)) { 5529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Map the current scatter buffer */ 5579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat local_irq_save(flags); 5589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat buffer = kmap_atomic(sg_page(host->pio.sg), 5599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat KM_BIO_SRC_IRQ) + host->pio.sg->offset; 5609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat buffer += host->pio.sg_off; 5619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain = host->pio.sg->length - host->pio.sg_off; 5629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = 0; 5639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE) 5649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = msmsdcc_pio_read(host, buffer, remain); 5659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_TXACTIVE) 5669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = msmsdcc_pio_write(host, buffer, remain, status); 5679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Unmap the buffer */ 5699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat kunmap_atomic(buffer, KM_BIO_SRC_IRQ); 5709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat local_irq_restore(flags); 5719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off += len; 5739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_remain -= len; 5749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered += len; 5759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= len; 5769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) { 5789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* This sg page is full - do some housekeeping */ 5799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE && host->curr.user_pages) 5809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat flush_dcache_page(sg_page(host->pio.sg)); 5819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!--host->pio.sg_len) { 5839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->pio, 0, sizeof(host->pio)); 5849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Advance to next sg */ 5889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg++; 5899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off = 0; 5909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5928b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 5939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (1); 5949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) 5968b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); 5979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->curr.xfer_remain) 5998b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCIMASK1); 6009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_HANDLED; 6029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 6039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) 6059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 6069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_command *cmd = host->curr.cmd; 6079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 6098b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); 6108b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); 6118b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); 6128b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); 6139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat del_timer(&host->command_timer); 6159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_CMDTIMEOUT) { 6169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->error = -ETIMEDOUT; 6179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_CMDCRCFAIL && 6189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->flags & MMC_RSP_CRC) { 6190a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); 6209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->error = -EILSEQ; 6219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!cmd->data || cmd->error) { 6249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.data && host->dma.sg) 6259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msm_dmov_stop_cmd(host->dma.channel, 6269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat &host->dma.hdr, 0); 6279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else if (host->curr.data) { /* Non DMA */ 6289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 6299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_request_end(host, cmd->mrq); 6309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else /* host->data == NULL */ 6319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_request_end(host, cmd->mrq); 6329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (!(cmd->data->flags & MMC_DATA_READ)) 6339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_data(host, cmd->data); 6349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 6359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 636b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesstatic void 637b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesmsmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, 638b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches void __iomem *base) 639b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches{ 640b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches struct mmc_data *data = host->curr.data; 641b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 642b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data) 643b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches return; 644b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 645b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* Check for data errors */ 646b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | 647b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches MCI_TXUNDERRUN | MCI_RXOVERRUN)) { 648b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_data_err(host, data, status); 649b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.data_xfered = 0; 650b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (host->dma.sg) 651b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msm_dmov_stop_cmd(host->dma.channel, 652b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches &host->dma.hdr, 0); 653b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else { 654b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_stop_data(host); 655b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->stop) 656b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_request_end(host, data->mrq); 657b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else 658b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_start_command(host, data->stop, 0); 659b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 660b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 661b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 662b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* Check for data done */ 663b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!host->curr.got_dataend && (status & MCI_DATAEND)) 664b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.got_dataend = 1; 665b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 666b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND)) 667b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.got_datablkend = 1; 668b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 669b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* 670b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * If DMA is still in progress, we complete via the completion handler 671b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches */ 672b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (host->curr.got_dataend && host->curr.got_datablkend && 673b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches !host->dma.busy) { 674b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* 675b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * There appears to be an issue in the controller where 676b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * if you request a small block transfer (< fifo size), 677b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * you may get your DATAEND/DATABLKEND irq without the 678b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * PIO data irq. 679b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * 680b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * Check to see if there is still data to be read, 681b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * and simulate a PIO irq. 682b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches */ 683b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) 684b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_pio_irq(1, host); 685b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 686b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_stop_data(host); 687b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->error) 688b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.data_xfered = host->curr.xfer_size; 689b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 690b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->stop) 691b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_request_end(host, data->mrq); 692b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else 693b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_start_command(host, data->stop, 0); 694b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 695b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches} 696b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 6979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t 6989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_irq(int irq, void *dev_id) 6999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 7009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 7019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 7029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 status; 7039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int ret = 0; 7049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int cardint = 0; 7059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock(&host->lock); 7079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 7098b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat struct mmc_data *data; 7108b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 7118b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status &= (msmsdcc_readl(host, MMCIMASK0) | 7128b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat MCI_DATABLOCKENDMASK); 7138b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, status, MMCICLEAR); 7149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 715865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (status & MCI_SDIOINTR) 716865c8064a2fb07100525097983966b8e789bde1aSan Mehat status &= ~MCI_SDIOINTR; 717865c8064a2fb07100525097983966b8e789bde1aSan Mehat 718865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!status) 719865c8064a2fb07100525097983966b8e789bde1aSan Mehat break; 720865c8064a2fb07100525097983966b8e789bde1aSan Mehat 721b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_handle_irq_data(host, status, base); 7229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | 7249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_CMDTIMEOUT) && host->curr.cmd) { 7259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_do_cmdirq(host, status); 7269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_SDIOINTOPER) { 7299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cardint = 1; 7309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status &= ~MCI_SDIOINTOPER; 7319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = 1; 7339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (status); 7349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock(&host->lock); 7369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 7389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * We have to delay handling the card interrupt as it calls 7399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * back into the driver. 7409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 7419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cardint) 7429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_signal_sdio_irq(host->mmc); 7439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_RETVAL(ret); 7459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 7469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 7489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) 7499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 7509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 7519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 7529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat WARN_ON(host->curr.mrq != NULL); 7549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat WARN_ON(host->pwr == 0); 7559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 7579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.reqs++; 7599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->eject) { 7619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) { 7629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = 0; 7639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = mrq->data->blksz * 7649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->blocks; 7659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 7669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = -ENOMEDIUM; 7679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 7699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(mmc, mrq); 7709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 7719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = mrq; 774865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!host->clks_on) 775865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 1); 7769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data && mrq->data->flags & MMC_DATA_READ) 7789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_data(host, mrq->data); 7799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_command(host, mrq->cmd, 0); 7819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->cmdpoll && !msmsdcc_spin_on_status(host, 7839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, 7849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat CMD_SPINMAX)) { 7858b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat uint32_t status = msmsdcc_readl(host, MMCISTATUS); 7869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_do_cmdirq(host, status); 7878b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 7888b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, 7898b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat MMCICLEAR); 7909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmdpoll_hits++; 7919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 7929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmdpoll_misses++; 7939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mod_timer(&host->command_timer, jiffies + HZ); 7949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 7959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 7969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 7979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 7999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 8009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 8019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 8029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 clk = 0, pwr = 0; 8039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int rc; 8044adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat unsigned long flags; 8059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8064adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat spin_lock_irqsave(&host->lock, flags); 807865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!host->clks_on) 808865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 1); 8099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 810865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (ios->clock) { 8119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->clock != host->clk_rate) { 8129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = clk_set_rate(host->clk, ios->clock); 8139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (rc < 0) 8140a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Error setting clock rate (%d)\n", 8150a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), rc); 8169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 8179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk_rate = ios->clock; 8189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= MCI_CLK_ENABLE; 8209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->bus_width == MMC_BUS_WIDTH_4) 8239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (2 << 10); /* Set WIDEBUS */ 8249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->clock > 400000 && msmsdcc_pwrsave) 8269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 9); /* PWRSAVE */ 8279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 12); /* FLOW_ENA */ 8299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 15); /* feedback clock */ 8309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->plat->translate_vdd) 8329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); 8339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat switch (ios->power_mode) { 8359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_OFF: 8369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 8379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_UP: 8389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_PWR_UP; 8399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 8409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_ON: 8419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_PWR_ON; 8429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 8439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 8469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_OD; 8479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8488b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, clk, MMCICLOCK); 8499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->pwr != pwr) { 8519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pwr = pwr; 8528b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, pwr, MMCIPOWER); 8539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 854865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->clks_on) 8554adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 0); 8564adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat spin_unlock_irqrestore(&host->lock, flags); 8579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 8589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) 8609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 8619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 8629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 8639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 status; 8649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 8669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_sdioirq == 1) { 8678b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCIMASK0); 8689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (enable) 8699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status |= MCI_SDIOINTOPERMASK; 8709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 8719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status &= ~MCI_SDIOINTOPERMASK; 8729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->saved_irq0mask = status; 8738b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, status, MMCIMASK0); 8749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 8769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 8779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic const struct mmc_host_ops msmsdcc_ops = { 8799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .request = msmsdcc_request, 8809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .set_ios = msmsdcc_set_ios, 8819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .enable_sdio_irq = msmsdcc_enable_sdio_irq, 8829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}; 8839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 8859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_check_status(unsigned long data) 8869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 8879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = (struct msmsdcc_host *)data; 8889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int status; 8899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->plat->status) { 8919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, 0); 8929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 8939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = host->plat->status(mmc_dev(host->mmc)); 8969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->eject = !status; 8979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status ^ host->oldstat) { 8980a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Slot status change detected (%d -> %d)\n", 8990a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), host->oldstat, status); 9009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status) 9019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, (5 * HZ) / 2); 9029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 9039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, 0); 9049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->oldstat = status; 9079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout: 9099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->timer.function) 9109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mod_timer(&host->timer, jiffies + HZ); 9119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t 9149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_platform_status_irq(int irq, void *dev_id) 9159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 9179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_DEBUG "%s: %d\n", __func__, irq); 9199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_check_status((unsigned long) host); 9209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_HANDLED; 9219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 9249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_status_notify_cb(int card_present, void *dev_id) 9259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 9279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), 9299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat card_present); 9309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_check_status((unsigned long) host); 9319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 933865c8064a2fb07100525097983966b8e789bde1aSan Mehatstatic void 934865c8064a2fb07100525097983966b8e789bde1aSan Mehatmsmsdcc_busclk_expired(unsigned long _data) 935865c8064a2fb07100525097983966b8e789bde1aSan Mehat{ 936865c8064a2fb07100525097983966b8e789bde1aSan Mehat struct msmsdcc_host *host = (struct msmsdcc_host *) _data; 937865c8064a2fb07100525097983966b8e789bde1aSan Mehat unsigned long flags; 938865c8064a2fb07100525097983966b8e789bde1aSan Mehat 939865c8064a2fb07100525097983966b8e789bde1aSan Mehat spin_lock_irqsave(&host->lock, flags); 940865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->clks_on) 941865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 0); 942865c8064a2fb07100525097983966b8e789bde1aSan Mehat 943865c8064a2fb07100525097983966b8e789bde1aSan Mehat spin_unlock_irqrestore(&host->lock, flags); 944865c8064a2fb07100525097983966b8e789bde1aSan Mehat} 945865c8064a2fb07100525097983966b8e789bde1aSan Mehat 9469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat/* 9479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * called when a command expires. 9489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Dump some debugging, and then error 9499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * out the transaction. 9509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 9519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 9529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_command_expired(unsigned long _data) 9539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = (struct msmsdcc_host *) _data; 9559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_request *mrq; 9569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 9579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 9599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq = host->curr.mrq; 9609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq) { 9629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 9639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 9649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9668b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat pr_err("%s: Controller lockup detected\n", 9678b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat mmc_hostname(host->mmc)); 9689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = -ETIMEDOUT; 9699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 9709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9718b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCICOMMAND); 9729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 9749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 9759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 976865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->clks_on) 977865c8064a2fb07100525097983966b8e789bde1aSan Mehat msmsdcc_enable_clocks(host, 0); 9789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 9799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 9809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 9839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_init_dma(struct msmsdcc_host *host) 9849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data)); 9869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.host = host; 9879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.channel = -1; 9889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->dmares) 9909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENODEV; 9919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.nc = dma_alloc_coherent(NULL, 9939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat sizeof(struct msmsdcc_nc_dmadata), 9949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat &host->dma.nc_busaddr, 9959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat GFP_KERNEL); 9969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.nc == NULL) { 9970a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("Unable to allocate DMA buffer\n"); 9989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOMEM; 9999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata)); 10019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.cmd_busaddr = host->dma.nc_busaddr; 10029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.cmdptr_busaddr = host->dma.nc_busaddr + 10039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat offsetof(struct msmsdcc_nc_dmadata, cmdptr); 10049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.channel = host->dmares->start; 10059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 10079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ 10109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 10119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatdo_resume_work(struct work_struct *work) 10129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = 10149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat container_of(work, struct msmsdcc_host, resume_task); 10159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = host->mmc; 10169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 10189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_resume_host(mmc); 10199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 10209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat enable_irq(host->stat_irq); 10219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#endif 10249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 10269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_probe(struct platform_device *pdev) 10279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_platform_data *plat = pdev->dev.platform_data; 10299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host; 10309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc; 10319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *cmd_irqres = NULL; 10329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *pio_irqres = NULL; 10339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *stat_irqres = NULL; 10349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *memres = NULL; 10359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *dmares = NULL; 10369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int ret; 10379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* must have platform data */ 10399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!plat) { 10400a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Platform data not available\n", __func__); 10419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -EINVAL; 10429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 10439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (pdev->id < 1 || pdev->id > 4) 10469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 10479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (pdev->resource == NULL || pdev->num_resources < 2) { 10490a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Invalid resource\n", __func__); 10509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENXIO; 10519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); 10559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 10569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "cmd_irq"); 10579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 10589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "pio_irq"); 10599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 10609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "status_irq"); 10619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!cmd_irqres || !pio_irqres || !memres) { 10630a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Invalid resource\n", __func__); 10649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENXIO; 10659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 10689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup our host structure 10699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 10709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); 10729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mmc) { 10739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -ENOMEM; 10749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 10759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host = mmc_priv(mmc); 10789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pdev_id = pdev->id; 10799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->plat = plat; 10809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->mmc = mmc; 10819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->cmdpoll = 1; 10839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1084865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->use_bustimer = 1; 1085865c8064a2fb07100525097983966b8e789bde1aSan Mehat 10869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->base = ioremap(memres->start, PAGE_SIZE); 10879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->base) { 10889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -ENOMEM; 10899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 10909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->cmd_irqres = cmd_irqres; 10939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio_irqres = pio_irqres; 10949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->memres = memres; 10959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dmares = dmares; 10969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_init(&host->lock); 10979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 10999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup DMA 11009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_init_dma(host); 11029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11034adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat /* Get our clocks */ 11049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pclk = clk_get(&pdev->dev, "sdc_pclk"); 11059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (IS_ERR(host->pclk)) { 11069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = PTR_ERR(host->pclk); 11079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto host_free; 11089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk = clk_get(&pdev->dev, "sdc_clk"); 11119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (IS_ERR(host->clk)) { 11129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = PTR_ERR(host->clk); 11134adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat goto pclk_put; 11149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11164adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat /* Enable clocks */ 11174adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat ret = msmsdcc_enable_clocks(host, 1); 11189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 11199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_put; 11209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = clk_set_rate(host->clk, msmsdcc_fmin); 11229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) { 11230a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); 11249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_disable; 11259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11274adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat host->pclk_rate = clk_get_rate(host->pclk); 11289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk_rate = clk_get_rate(host->clk); 11299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup MMC host structure 11329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->ops = &msmsdcc_ops; 11349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->f_min = msmsdcc_fmin; 11359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->f_max = msmsdcc_fmax; 11369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->ocr_avail = plat->ocr_mask; 11379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_4bit) 11399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_4_BIT_DATA; 11409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_sdioirq) 11419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_SDIO_IRQ; 11429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; 11439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_phys_segs = NR_SG; 11459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_hw_segs = NR_SG; 11469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */ 11479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_blk_count = 65536; 11489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ 11509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_seg_size = mmc->max_req_size; 11519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11528b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCIMASK0); 11538b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); 11549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11558b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); 11569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->saved_irq0mask = MCI_IRQENABLE; 11579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup card detect change 11609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->timer, 0, sizeof(host->timer)); 11639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) { 11659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long irqflags = IRQF_SHARED | 11669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (stat_irqres->flags & IRQF_TRIGGER_MASK); 11679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stat_irq = stat_irqres->start; 11699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(host->stat_irq, 11709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_platform_status_irq, 11719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat irqflags, 11729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (slot)", 11739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host); 11749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) { 11750a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unable to get slot IRQ %d (%d)\n", 11760a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->stat_irq, ret); 11779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_disable; 11789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (plat->register_status_notify) { 11809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat plat->register_status_notify(msmsdcc_status_notify_cb, host); 11819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (!plat->status) 11820a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: No card detect facilities available\n", 11839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(mmc)); 11849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else { 11859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat init_timer(&host->timer); 11869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.data = (unsigned long)host; 11879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.function = msmsdcc_check_status; 11889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.expires = jiffies + HZ; 11899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat add_timer(&host->timer); 11909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (plat->status) { 11939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->oldstat = host->plat->status(mmc_dev(host->mmc)); 11949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->eject = !host->oldstat; 11959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup a command timer. We currently need this due to 11999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * some 'strange' timeout / error handling situations. 12009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 12019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat init_timer(&host->command_timer); 12029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->command_timer.data = (unsigned long) host; 12039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->command_timer.function = msmsdcc_command_expired; 12049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1205865c8064a2fb07100525097983966b8e789bde1aSan Mehat init_timer(&host->busclk_timer); 1206865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->busclk_timer.data = (unsigned long) host; 1207865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->busclk_timer.function = msmsdcc_busclk_expired; 1208865c8064a2fb07100525097983966b8e789bde1aSan Mehat 12099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, 12109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (cmd)", host); 12119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 12129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto stat_irq_free; 12139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, 12159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (pio)", host); 12169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 12179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto cmd_irq_free; 12189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_set_drvdata(pdev, mmc); 12209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_add_host(mmc); 12219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12220a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", 12230a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), (unsigned long long)memres->start, 12240a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (unsigned int) cmd_irqres->start, 12250a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (unsigned int) host->stat_irq, host->dma.channel); 12260a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc), 12270a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); 12280a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", 12290a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); 12300a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); 12310a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Power save feature enable = %d\n", 12320a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), msmsdcc_pwrsave); 12339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.channel != -1) { 12350a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", 12360a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); 12370a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", 12380a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->dma.cmd_busaddr, 12390a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches host->dma.cmdptr_busaddr); 12409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 12410a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc)); 12429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->timer.function) 12430a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); 12449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 12469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd_irq_free: 12479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat free_irq(cmd_irqres->start, host); 12489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat stat_irq_free: 12499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 12509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat free_irq(host->stat_irq, host); 12519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_disable: 12524adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 0); 12539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put: 12549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put(host->clk); 12559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pclk_put: 12569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put(host->pclk); 12579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host_free: 12589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_free_host(mmc); 12599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat out: 12609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return ret; 12619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 12629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 12649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_suspend(struct platform_device *dev, pm_message_t state) 12659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 12669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = mmc_get_drvdata(dev); 12679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int rc = 0; 12689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 12709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 12719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 12739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat disable_irq(host->stat_irq); 12749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) 12769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = mmc_suspend_host(mmc, state); 12779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!rc) { 12788b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCIMASK0); 12799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12804adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat if (host->clks_on) 12814adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 0); 12829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 12839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 12849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return rc; 12859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 12869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 12889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_resume(struct platform_device *dev) 12899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 12909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = mmc_get_drvdata(dev); 12919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 12929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 12949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 12959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 12979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12984adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat if (!host->clks_on) 12994adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat msmsdcc_enable_clocks(host, 1); 13009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13018b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); 13029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 13049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) 13069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_resume_host(mmc); 13075b8a2fb34f5670b1f07483bfa40de9ce539dbdb2Roel Kluin if (host->stat_irq) 13089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat enable_irq(host->stat_irq); 13099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 13109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 13119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic struct platform_driver msmsdcc_driver = { 13149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .probe = msmsdcc_probe, 13159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .suspend = msmsdcc_suspend, 13169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .resume = msmsdcc_resume, 13179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .driver = { 13189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .name = "msm_sdcc", 13199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat }, 13209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}; 13219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int __init msmsdcc_init(void) 13239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return platform_driver_register(&msmsdcc_driver); 13259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void __exit msmsdcc_exit(void) 13289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat platform_driver_unregister(&msmsdcc_driver); 13309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_init(msmsdcc_init); 13339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_exit(msmsdcc_exit); 13349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13359d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); 13369d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_LICENSE("GPL"); 1337