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.
656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *  Copyright (C) 2009, Code Aurora Forum. All Rights Reserved.
79d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat *
89d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * This program is free software; you can redistribute it and/or modify
99d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * it under the terms of the GNU General Public License version 2 as
109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * published by the Free Software Foundation.
119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat *
129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Based on mmci.c
139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat *
149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Author: San Mehat (san@android.com)
159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat *
169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */
179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/module.h>
199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/moduleparam.h>
209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/init.h>
219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/ioport.h>
229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/device.h>
239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/interrupt.h>
249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/delay.h>
259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/err.h>
269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/highmem.h>
279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/log2.h>
289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/mmc/host.h>
299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/mmc/card.h>
30b3fa579118b239e218e690f5ef76870aff6fe738San Mehat#include <linux/mmc/sdio.h>
319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/clk.h>
329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/scatterlist.h>
339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/platform_device.h>
349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/dma-mapping.h>
359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/debugfs.h>
369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/io.h>
379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <linux/memory.h>
385a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
397a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala#include <linux/gpio.h>
409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/cacheflush.h>
429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/div64.h>
439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/sizes.h>
449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
453989d17847071fa94c93299805a9cca27cf65d26Pavel Machek#include <mach/mmc.h>
469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <mach/msm_iomap.h>
479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <mach/dma.h>
48b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala#include <mach/clk.h>
499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include "msm_sdcc.h"
519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define DRIVER_NAME "msm-sdcc"
539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5424bbd7d5b422cde6a149ac2f9ac6e61e66536532San Mehat#define BUSCLK_PWRSAVE 1
55c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat#define BUSCLK_TIMEOUT (HZ)
569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_fmin = 144000;
579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_fmax = 50000000;
589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_4bit = 1;
599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_pwrsave = 1;
609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_piopoll = 1;
619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_sdioirq;
629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define PIO_SPINMAX 30
649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define CMD_SPINMAX 20
659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
66865c8064a2fb07100525097983966b8e789bde1aSan Mehat
67d0719e59f4ad96616f7c02ef0201667e41778c88San Mehatstatic inline void
68c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehatmsmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr)
69865c8064a2fb07100525097983966b8e789bde1aSan Mehat{
70c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	WARN_ON(!host->clks_on);
718b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat
72f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat	BUG_ON(host->curr.mrq);
73f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat
74c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	if (deferr) {
75c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat		mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
76865c8064a2fb07100525097983966b8e789bde1aSan Mehat	} else {
77c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat		del_timer_sync(&host->busclk_timer);
78d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		/* Need to check clks_on again in case the busclk
79d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		 * timer fired
80d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		 */
81d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		if (host->clks_on) {
82d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat			clk_disable(host->clk);
83d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat			clk_disable(host->pclk);
84d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat			host->clks_on = 0;
85d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		}
86865c8064a2fb07100525097983966b8e789bde1aSan Mehat	}
87c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat}
88c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat
89c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehatstatic inline int
90c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehatmsmsdcc_enable_clocks(struct msmsdcc_host *host)
91c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat{
92c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	int rc;
93c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat
94c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	del_timer_sync(&host->busclk_timer);
95c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat
96d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat	if (!host->clks_on) {
97d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		rc = clk_enable(host->pclk);
98d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		if (rc)
99d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat			return rc;
100d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		rc = clk_enable(host->clk);
101d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		if (rc) {
102d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat			clk_disable(host->pclk);
103d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat			return rc;
104d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		}
105d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		udelay(1 + ((3 * USEC_PER_SEC) /
106d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		       (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
107d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		host->clks_on = 1;
108c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	}
109865c8064a2fb07100525097983966b8e789bde1aSan Mehat	return 0;
110865c8064a2fb07100525097983966b8e789bde1aSan Mehat}
111865c8064a2fb07100525097983966b8e789bde1aSan Mehat
1128b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatstatic inline unsigned int
1138b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatmsmsdcc_readl(struct msmsdcc_host *host, unsigned int reg)
1148b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat{
1158b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	return readl(host->base + reg);
1168b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat}
1178b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat
1188b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatstatic inline void
1198b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatmsmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg)
1208b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat{
1218b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	writel(data, host->base + reg);
1228b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	/* 3 clk delay required! */
1238b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	udelay(1 + ((3 * USEC_PER_SEC) /
1248b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	       (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
1258b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat}
126865c8064a2fb07100525097983966b8e789bde1aSan Mehat
1279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
1289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
1299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		      u32 c);
1309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
131b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummalastatic void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
132b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala{
133b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	u32	mci_clk = 0;
134b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	u32	mci_mask0 = 0;
135b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	int	ret = 0;
136b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala
137b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	/* Save the controller state */
138b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	mci_clk = readl(host->base + MMCICLOCK);
139b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	mci_mask0 = readl(host->base + MMCIMASK0);
140b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala
141b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	/* Reset the controller */
142b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	ret = clk_reset(host->clk, CLK_RESET_ASSERT);
143b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	if (ret)
144b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala		pr_err("%s: Clock assert failed at %u Hz with err %d\n",
145b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala				mmc_hostname(host->mmc), host->clk_rate, ret);
146b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala
147b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
148b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	if (ret)
149b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala		pr_err("%s: Clock deassert failed at %u Hz with err %d\n",
150b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala				mmc_hostname(host->mmc), host->clk_rate, ret);
151b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala
152b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	pr_info("%s: Controller has been re-initialiazed\n",
153b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala			mmc_hostname(host->mmc));
154b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala
155b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	/* Restore the contoller state */
156b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	writel(host->pwr, host->base + MMCIPOWER);
157b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	writel(mci_clk, host->base + MMCICLOCK);
158b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	writel(mci_mask0, host->base + MMCIMASK0);
159b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	ret = clk_set_rate(host->clk, host->clk_rate);
160b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala	if (ret)
161b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala		pr_err("%s: Failed to set clk rate %u Hz (%d)\n",
162b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala				mmc_hostname(host->mmc), host->clk_rate, ret);
163b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala}
164b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala
1659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
1669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
1679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
1689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	BUG_ON(host->curr.data);
1699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.mrq = NULL;
1719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.cmd = NULL;
1729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (mrq->data)
1749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mrq->data->bytes_xfered = host->curr.data_xfered;
1759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (mrq->cmd->error == -ETIMEDOUT)
1769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mdelay(5);
1779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
178f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat#if BUSCLK_PWRSAVE
179c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	msmsdcc_disable_clocks(host, 1);
180f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat#endif
1819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	/*
1829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * Need to drop the host lock here; mmc_request_done may call
1839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * back into the driver...
1849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 */
1859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_unlock(&host->lock);
1869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc_request_done(host->mmc, mrq);
1879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_lock(&host->lock);
1889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
1899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
1919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_stop_data(struct msmsdcc_host *host)
1929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
1939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.data = NULL;
1940c521ccbd0c9ad5623ff9b37b20b3ff9d4ad65a7Sahitya Tummala	host->curr.got_dataend = 0;
1959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
1969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatuint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
1989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
199edd4dd0e987919ed672376c5c73c32aacfc24f39Sahitya Tummala	return host->memres->start + MMCIFIFO;
2009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
2019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
20256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic inline void
20356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) {
20456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat       msmsdcc_writel(host, arg, MMCIARGUMENT);
20556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat       msmsdcc_writel(host, c, MMCICOMMAND);
20656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat}
20756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
20856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic void
20956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
21056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat{
2116ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat	struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data;
21256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
2136ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat	msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER);
214d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat	msmsdcc_writel(host, (unsigned int)host->curr.xfer_size,
215d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		       MMCIDATALENGTH);
2164a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala	msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) &
2174a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala			(~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0);
2186ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat	msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL);
21956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
2206ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat	if (host->cmd_cmd) {
2216ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat		msmsdcc_start_command_exec(host,
2226ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat					   (u32) host->cmd_cmd->arg,
2236ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat					   (u32) host->cmd_c);
2246ac9ea69069804d357064357d0082b0eab4c87ceSan Mehat	}
22556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	host->dma.active = 1;
22656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat}
22756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
2289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
22962612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummalamsmsdcc_dma_complete_tlet(unsigned long data)
2309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
23162612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	struct msmsdcc_host *host = (struct msmsdcc_host *)data;
2329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned long		flags;
2339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct mmc_request	*mrq;
23462612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	struct msm_dmov_errdata err;
2359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
2369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_lock_irqsave(&host->lock, flags);
23756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	host->dma.active = 0;
23856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
23962612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	err = host->dma.err;
2409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mrq = host->curr.mrq;
2419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	BUG_ON(!mrq);
242b3b0ca84cfec581fba3ea8efaa8052cb5e6fc857San Mehat	WARN_ON(!mrq->data);
2439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
24462612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	if (!(host->dma.result & DMOV_RSLT_VALID)) {
2450a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("msmsdcc: Invalid DataMover result\n");
2469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		goto out;
2479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
2489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
24962612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	if (host->dma.result & DMOV_RSLT_DONE) {
2509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->curr.data_xfered = host->curr.xfer_size;
2519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else {
2529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		/* Error or flush  */
25362612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala		if (host->dma.result & DMOV_RSLT_ERROR)
2540a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			pr_err("%s: DMA error (0x%.8x)\n",
25562612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala			       mmc_hostname(host->mmc), host->dma.result);
25662612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala		if (host->dma.result & DMOV_RSLT_FLUSH)
2570a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			pr_err("%s: DMA channel flushed (0x%.8x)\n",
25862612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala			       mmc_hostname(host->mmc), host->dma.result);
25962612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala
26062612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala		pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
26162612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala		       err.flush[0], err.flush[1], err.flush[2],
26262612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala		       err.flush[3], err.flush[4], err.flush[5]);
263b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala
264b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala		msmsdcc_reset_and_restore(host);
2659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (!mrq->data->error)
2669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mrq->data->error = -EIO;
2679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
2689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
2699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		     host->dma.dir);
2709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
2719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.sg = NULL;
27256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	host->dma.busy = 0;
2739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
2740c521ccbd0c9ad5623ff9b37b20b3ff9d4ad65a7Sahitya Tummala	if (host->curr.got_dataend || mrq->data->error) {
2759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
2769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		/*
2779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		 * If we've already gotten our DATAEND / DATABLKEND
2789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		 * for this request, then complete it through here.
2799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		 */
2809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		msmsdcc_stop_data(host);
2819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
2829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (!mrq->data->error)
2839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			host->curr.data_xfered = host->curr.xfer_size;
2849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (!mrq->data->stop || mrq->cmd->error) {
2859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			host->curr.mrq = NULL;
2869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			host->curr.cmd = NULL;
2879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mrq->data->bytes_xfered = host->curr.data_xfered;
2889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
2899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			spin_unlock_irqrestore(&host->lock, flags);
290f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat#if BUSCLK_PWRSAVE
291c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat			msmsdcc_disable_clocks(host, 1);
292f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat#endif
2939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mmc_request_done(host->mmc, mrq);
2949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			return;
2959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		} else
2969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			msmsdcc_start_command(host, mrq->data->stop, 0);
2979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
2989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
2999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout:
3009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_unlock_irqrestore(&host->lock, flags);
3019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return;
3029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
3039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
30462612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummalastatic void
30562612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummalamsmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
30662612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala			  unsigned int result,
30762612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala			  struct msm_dmov_errdata *err)
30862612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala{
30962612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	struct msmsdcc_dma_data	*dma_data =
31062612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala		container_of(cmd, struct msmsdcc_dma_data, hdr);
31162612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	struct msmsdcc_host *host = dma_data->host;
31262612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala
31362612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	dma_data->result = result;
31462612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	if (err)
31562612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala		memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
31662612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala
31762612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	tasklet_schedule(&host->dma_tlet);
31862612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala}
31962612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala
3209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
3219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
3229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->dma.channel == -1)
3239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -ENOENT;
3249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
3259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if ((data->blksz * data->blocks) < MCI_FIFOSIZE)
3269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -EINVAL;
3279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if ((data->blksz * data->blocks) % MCI_FIFOSIZE)
3289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -EINVAL;
3299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return 0;
3309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
3319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
3329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
3339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
3349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_nc_dmadata *nc;
3359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	dmov_box *box;
3369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	uint32_t rows;
3379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	uint32_t crci;
3389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned int n;
3399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	int i, rc;
3409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct scatterlist *sg = data->sg;
3419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
3429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	rc = validate_dma(host, data);
3439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (rc)
3449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return rc;
3459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
3469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.sg = data->sg;
3479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.num_ents = data->sg_len;
3489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
34956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat       BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
35056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
3519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	nc = host->dma.nc;
3529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
35375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches	switch (host->pdev_id) {
35475d145283b2e42619d7ee1e00b78466bacd51808Joe Perches	case 1:
3559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		crci = MSMSDCC_CRCI_SDC1;
35675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches		break;
35775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches	case 2:
3589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		crci = MSMSDCC_CRCI_SDC2;
35975d145283b2e42619d7ee1e00b78466bacd51808Joe Perches		break;
36075d145283b2e42619d7ee1e00b78466bacd51808Joe Perches	case 3:
3619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		crci = MSMSDCC_CRCI_SDC3;
36275d145283b2e42619d7ee1e00b78466bacd51808Joe Perches		break;
36375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches	case 4:
3649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		crci = MSMSDCC_CRCI_SDC4;
36575d145283b2e42619d7ee1e00b78466bacd51808Joe Perches		break;
36675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches	default:
3679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->dma.sg = NULL;
3689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->dma.num_ents = 0;
3699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -ENOENT;
3709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
3719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
3729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (data->flags & MMC_DATA_READ)
3739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->dma.dir = DMA_FROM_DEVICE;
3749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	else
3759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->dma.dir = DMA_TO_DEVICE;
3769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
3779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.user_pages = 0;
3789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
3799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	box = &nc->cmd[0];
3809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
381208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	/* location of command block must be 64 bit aligned */
382208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	BUG_ON(host->dma.cmd_busaddr & 0x07);
383208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker
384208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
385208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
386208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker			       DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
387208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
388208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker
389208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
390208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker			host->dma.num_ents, host->dma.dir);
391208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	if (n == 0) {
392a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S		pr_err("%s: Unable to map in all sg elements\n",
393208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker			mmc_hostname(host->mmc));
394208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker		host->dma.sg = NULL;
395208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker		host->dma.num_ents = 0;
396208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker		return -ENOMEM;
397208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	}
398208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker
399208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker	for_each_sg(host->dma.sg, sg, n, i) {
400208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker
401208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker		box->cmd = CMD_MODE_BOX;
40256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
403208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker		if (i == n - 1)
4049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->cmd |= CMD_LC;
4059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
4069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			(sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
4079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			(sg_dma_len(sg) / MCI_FIFOSIZE) ;
4089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (data->flags & MMC_DATA_READ) {
4109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->src_row_addr = msmsdcc_fifo_addr(host);
4119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->dst_row_addr = sg_dma_address(sg);
4129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->src_dst_len = (MCI_FIFOSIZE << 16) |
4149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat					   (MCI_FIFOSIZE);
4159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->row_offset = MCI_FIFOSIZE;
4169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->num_rows = rows * ((1 << 16) + 1);
4189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->cmd |= CMD_SRC_CRCI(crci);
4199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		} else {
4209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->src_row_addr = sg_dma_address(sg);
4219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->dst_row_addr = msmsdcc_fifo_addr(host);
4229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->src_dst_len = (MCI_FIFOSIZE << 16) |
4249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat					   (MCI_FIFOSIZE);
4259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->row_offset = (MCI_FIFOSIZE << 16);
4269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->num_rows = rows * ((1 << 16) + 1);
4289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			box->cmd |= CMD_DST_CRCI(crci);
4299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		}
4309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		box++;
43156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	}
43256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
43356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	return 0;
43456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat}
43556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
43656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic int
43756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatsnoop_cccr_abort(struct mmc_command *cmd)
43856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat{
43956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if ((cmd->opcode == 52) &&
44056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	    (cmd->arg & 0x80000000) &&
44156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	    (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT))
44256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		return 1;
4439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return 0;
4449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
4459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
44756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_start_command_deferred(struct msmsdcc_host *host,
44856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat				struct mmc_command *cmd, u32 *c)
44956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat{
45056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	*c |= (cmd->opcode | MCI_CPSM_ENABLE);
45156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
45256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if (cmd->flags & MMC_RSP_PRESENT) {
45356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		if (cmd->flags & MMC_RSP_136)
45456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			*c |= MCI_CPSM_LONGRSP;
45556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		*c |= MCI_CPSM_RESPONSE;
45656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	}
45756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
45856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if (/*interrupt*/0)
45956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		*c |= MCI_CPSM_INTERRUPT;
46056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
46156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if ((((cmd->opcode == 17) || (cmd->opcode == 18))  ||
46256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	     ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
46356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	      (cmd->opcode == 53))
46456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		*c |= MCI_CSPM_DATCMD;
46556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
466d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala	if (host->prog_scan && (cmd->opcode == 12)) {
467d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala		*c |= MCI_CPSM_PROGENA;
468d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala		host->prog_enable = true;
469d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala	}
470d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala
47156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if (cmd == cmd->mrq->stop)
47256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		*c |= MCI_CSPM_MCIABORT;
47356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
47456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if (snoop_cccr_abort(cmd))
47556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		*c |= MCI_CSPM_MCIABORT;
47656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
47756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if (host->curr.cmd != NULL) {
478a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S		pr_err("%s: Overlapping command requests\n",
47956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			mmc_hostname(host->mmc));
48056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	}
48156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	host->curr.cmd = cmd;
48256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat}
48356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
48456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic void
48556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
48656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			struct mmc_command *cmd, u32 c)
4879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
4889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned int datactrl, timeout;
4899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned long long clks;
4909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned int pio_irqmask = 0;
4919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.data = data;
4939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.xfer_size = data->blksz * data->blocks;
4949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.xfer_remain = host->curr.xfer_size;
4959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.data_xfered = 0;
4969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.got_dataend = 0;
4979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
4989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	memset(&host->pio, 0, sizeof(host->pio));
4999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
5019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!msmsdcc_config_dma(host, data))
5039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		datactrl |= MCI_DPSM_DMAENABLE;
5049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	else {
5059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->pio.sg = data->sg;
5069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->pio.sg_len = data->sg_len;
5079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->pio.sg_off = 0;
5089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (data->flags & MMC_DATA_READ) {
5109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			pio_irqmask = MCI_RXFIFOHALFFULLMASK;
5119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			if (host->curr.xfer_remain < MCI_FIFOSIZE)
5129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				pio_irqmask |= MCI_RXDATAAVLBLMASK;
5139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		} else
5149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			pio_irqmask = MCI_TXFIFOHALFEMPTYMASK;
5159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
5169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (data->flags & MMC_DATA_READ)
5189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		datactrl |= MCI_DPSM_DIRECTION;
5199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
52056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	clks = (unsigned long long)data->timeout_ns * host->clk_rate;
52156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	do_div(clks, NSEC_PER_SEC);
52256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	timeout = data->timeout_clks + (unsigned int)clks*2 ;
5239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (datactrl & MCI_DPSM_DMAENABLE) {
52556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		/* Save parameters for the exec function */
52656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		host->cmd_timeout = timeout;
52756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		host->cmd_pio_irqmask = pio_irqmask;
52856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		host->cmd_datactrl = datactrl;
52956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		host->cmd_cmd = cmd;
53056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
53156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		host->dma.hdr.execute_func = msmsdcc_dma_exec_func;
53256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		host->dma.hdr.data = (void *)host;
5339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->dma.busy = 1;
53456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
53556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		if (cmd) {
53656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			msmsdcc_start_command_deferred(host, cmd, &c);
53756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			host->cmd_c = c;
53856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		}
5399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
540d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala		if (data->flags & MMC_DATA_WRITE)
541d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala			host->prog_scan = true;
54256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	} else {
54356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		msmsdcc_writel(host, timeout, MMCIDATATIMER);
5449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
54556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
54656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
5474a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala		msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) &
5484a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala				(~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0);
5494a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala
55056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		msmsdcc_writel(host, datactrl, MMCIDATACTRL);
55156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
55256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		if (cmd) {
55356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			/* Daisy-chain the command if requested */
55456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			msmsdcc_start_command(host, cmd, c);
55556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		}
5569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
5579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
5589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
5609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
5619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
5629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (cmd == cmd->mrq->stop)
5639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		c |= MCI_CSPM_MCIABORT;
5649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->stats.cmds++;
5669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
56756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	msmsdcc_start_command_deferred(host, cmd, &c);
56856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	msmsdcc_start_command_exec(host, cmd->arg, c);
5699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
5709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
5729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
5739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		 unsigned int status)
5749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
5759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (status & MCI_DATACRCFAIL) {
5760a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc));
5770a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: opcode 0x%.8x\n", __func__,
5789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		       data->mrq->cmd->opcode);
5790a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: blksz %d, blocks %d\n", __func__,
5809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		       data->blksz, data->blocks);
5819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		data->error = -EILSEQ;
5829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else if (status & MCI_DATATIMEOUT) {
5830a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Data timeout\n", mmc_hostname(host->mmc));
5849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		data->error = -ETIMEDOUT;
5859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else if (status & MCI_RXOVERRUN) {
5860a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
5879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		data->error = -EIO;
5889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else if (status & MCI_TXUNDERRUN) {
5890a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
5909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		data->error = -EIO;
5919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else {
5920a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Unknown error (0x%.8x)\n",
5930a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		       mmc_hostname(host->mmc), status);
5949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		data->error = -EIO;
5959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
5969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
5979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
5999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int
6009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
6019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
6029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	uint32_t	*ptr = (uint32_t *) buffer;
6039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	int		count = 0;
6049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
60571dd9106af54de0f758875fa4b595af42a327448Sahitya Tummala	if (remain % 4)
60671dd9106af54de0f758875fa4b595af42a327448Sahitya Tummala		remain = ((remain >> 2) + 1) << 2;
60771dd9106af54de0f758875fa4b595af42a327448Sahitya Tummala
6088b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
6098b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		*ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
6109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ptr++;
6119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		count += sizeof(uint32_t);
6129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		remain -=  sizeof(uint32_t);
6149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (remain == 0)
6159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			break;
6169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
6179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return count;
6189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
6199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int
6219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
6229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		  unsigned int remain, u32 status)
6239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
6249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	void __iomem *base = host->base;
6259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	char *ptr = buffer;
6269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	do {
62871dd9106af54de0f758875fa4b595af42a327448Sahitya Tummala		unsigned int count, maxcnt, sz;
6299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE :
6319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat						    MCI_FIFOHALFSIZE;
6329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		count = min(remain, maxcnt);
6339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
63471dd9106af54de0f758875fa4b595af42a327448Sahitya Tummala		sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
63571dd9106af54de0f758875fa4b595af42a327448Sahitya Tummala		writesl(base + MMCIFIFO, ptr, sz);
6369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ptr += count;
6379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		remain -= count;
6389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (remain == 0)
6409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			break;
6419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6428b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		status = msmsdcc_readl(host, MMCISTATUS);
6439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} while (status & MCI_TXFIFOHALFEMPTY);
6449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return ptr - buffer;
6469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
6479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int
6499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin)
6509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
6519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	while (maxspin) {
6528b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		if ((msmsdcc_readl(host, MMCISTATUS) & mask))
6539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			return 0;
6549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		udelay(1);
6559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		--maxspin;
6569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
6579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return -ETIMEDOUT;
6589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
6599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6601cd2296909e77702c68021ede9d87a1d967a6a99San Mehatstatic irqreturn_t
6619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_irq(int irq, void *dev_id)
6629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
6639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host	*host = dev_id;
6649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	uint32_t		status;
6654a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala	u32 mci_mask0;
6669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6678b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	status = msmsdcc_readl(host, MMCISTATUS);
6684a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala	mci_mask0 = msmsdcc_readl(host, MMCIMASK0);
6694a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala
6704a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala	if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0)
6714a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala		return IRQ_NONE;
6729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	do {
6749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		unsigned long flags;
6759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		unsigned int remain, len;
6769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		char *buffer;
6779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) {
6799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll)
6809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				break;
6819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			if (msmsdcc_spin_on_status(host,
6839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat						   (MCI_TXFIFOHALFEMPTY |
6849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat						   MCI_RXDATAAVLBL),
6859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat						   PIO_SPINMAX)) {
6869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				break;
6879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			}
6889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		}
6899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
6909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		/* Map the current scatter buffer */
6919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		local_irq_save(flags);
692482fce997e143a8d5429406fe066d31aa76ef70aCong Wang		buffer = kmap_atomic(sg_page(host->pio.sg))
693482fce997e143a8d5429406fe066d31aa76ef70aCong Wang				     + host->pio.sg->offset;
6949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		buffer += host->pio.sg_off;
6959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		remain = host->pio.sg->length - host->pio.sg_off;
6969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		len = 0;
6979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (status & MCI_RXACTIVE)
6989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			len = msmsdcc_pio_read(host, buffer, remain);
6999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (status & MCI_TXACTIVE)
7009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			len = msmsdcc_pio_write(host, buffer, remain, status);
7019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		/* Unmap the buffer */
703482fce997e143a8d5429406fe066d31aa76ef70aCong Wang		kunmap_atomic(buffer);
7049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		local_irq_restore(flags);
7059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->pio.sg_off += len;
7079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->curr.xfer_remain -= len;
7089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->curr.data_xfered += len;
7099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		remain -= len;
7109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (remain == 0) {
7129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			/* This sg page is full - do some housekeeping */
7139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			if (status & MCI_RXACTIVE && host->curr.user_pages)
7149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				flush_dcache_page(sg_page(host->pio.sg));
7159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			if (!--host->pio.sg_len) {
7179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				memset(&host->pio, 0, sizeof(host->pio));
7189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				break;
7199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			}
7209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			/* Advance to next sg */
7229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			host->pio.sg++;
7239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			host->pio.sg_off = 0;
7249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		}
7259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7268b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		status = msmsdcc_readl(host, MMCISTATUS);
7279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} while (1);
7289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE)
7304a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala		msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) |
7314a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala					MCI_RXDATAAVLBLMASK, MMCIMASK0);
7329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!host->curr.xfer_remain)
7344a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala		msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0,
7354a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala					MMCIMASK0);
7369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return IRQ_HANDLED;
7389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
7399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
7419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
7429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct mmc_command *cmd = host->curr.cmd;
7439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.cmd = NULL;
7458b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0);
7468b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1);
7478b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2);
7488b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3);
7499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (status & MCI_CMDTIMEOUT) {
7519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		cmd->error = -ETIMEDOUT;
7529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else if (status & MCI_CMDCRCFAIL &&
7539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		   cmd->flags & MMC_RSP_CRC) {
7540a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
7559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		cmd->error = -EILSEQ;
7569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
7579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
7589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!cmd->data || cmd->error) {
7599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (host->curr.data && host->dma.sg)
7609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			msm_dmov_stop_cmd(host->dma.channel,
7619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat					  &host->dma.hdr, 0);
7629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		else if (host->curr.data) { /* Non DMA */
763b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala			msmsdcc_reset_and_restore(host);
7649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			msmsdcc_stop_data(host);
7659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			msmsdcc_request_end(host, cmd->mrq);
766d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala		} else { /* host->data == NULL */
767d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala			if (!cmd->error && host->prog_enable) {
768d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala				if (status & MCI_PROGDONE) {
769d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala					host->prog_scan = false;
770d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala					host->prog_enable = false;
771d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala					msmsdcc_request_end(host, cmd->mrq);
772d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala				} else {
773d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala					host->curr.cmd = cmd;
774d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala				}
775d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala			} else {
776d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala				if (host->prog_enable) {
777d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala					host->prog_scan = false;
778d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala					host->prog_enable = false;
779d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala				}
780d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala				msmsdcc_request_end(host, cmd->mrq);
781d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala			}
782d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala		}
78356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	} else if (cmd->data)
78456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		if (!(cmd->data->flags & MMC_DATA_READ))
78556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat			msmsdcc_start_data(host, cmd->data,
78656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat						NULL, 0);
7879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
7889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
789b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesstatic void
790b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesmsmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
791b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			void __iomem *base)
792b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches{
793b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	struct mmc_data *data = host->curr.data;
794b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches
79556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
796d5137bdd91b8267ada3973806443013f4bf079f6Sahitya Tummala			MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) {
79756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		msmsdcc_do_cmdirq(host, status);
79856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	}
79956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat
800b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	if (!data)
801b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		return;
802b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches
803b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	/* Check for data errors */
804b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
805b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		      MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
806b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		msmsdcc_data_err(host, data, status);
807b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		host->curr.data_xfered = 0;
808b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		if (host->dma.sg)
809b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			msm_dmov_stop_cmd(host->dma.channel,
810b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches					  &host->dma.hdr, 0);
811b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		else {
812b08bb35d1a5ee5426198eb3a2861008c2e9e6fc4Sahitya Tummala			msmsdcc_reset_and_restore(host);
813b3b0ca84cfec581fba3ea8efaa8052cb5e6fc857San Mehat			if (host->curr.data)
814b3b0ca84cfec581fba3ea8efaa8052cb5e6fc857San Mehat				msmsdcc_stop_data(host);
815b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			if (!data->stop)
816b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches				msmsdcc_request_end(host, data->mrq);
817b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			else
818b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches				msmsdcc_start_command(host, data->stop, 0);
819b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		}
820b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	}
821b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches
822b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	/* Check for data done */
823b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	if (!host->curr.got_dataend && (status & MCI_DATAEND))
824b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		host->curr.got_dataend = 1;
825b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches
826b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	/*
827b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	 * If DMA is still in progress, we complete via the completion handler
828b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	 */
8290c521ccbd0c9ad5623ff9b37b20b3ff9d4ad65a7Sahitya Tummala	if (host->curr.got_dataend && !host->dma.busy) {
830b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		/*
831b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 * There appears to be an issue in the controller where
832b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 * if you request a small block transfer (< fifo size),
833b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 * you may get your DATAEND/DATABLKEND irq without the
834b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 * PIO data irq.
835b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 *
836b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 * Check to see if there is still data to be read,
837b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 * and simulate a PIO irq.
838b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		 */
839b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL)
840b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			msmsdcc_pio_irq(1, host);
841b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches
842b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		msmsdcc_stop_data(host);
843b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		if (!data->error)
844b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			host->curr.data_xfered = host->curr.xfer_size;
845b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches
846b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		if (!data->stop)
847b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			msmsdcc_request_end(host, data->mrq);
848b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		else
849b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches			msmsdcc_start_command(host, data->stop, 0);
850b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches	}
851b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches}
852b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches
8539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t
8549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_irq(int irq, void *dev_id)
8559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
8569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host	*host = dev_id;
8579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	void __iomem		*base = host->base;
8589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	u32			status;
8599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	int			ret = 0;
8609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	int			cardint = 0;
8619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
8629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_lock(&host->lock);
8639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
8649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	do {
8658b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		status = msmsdcc_readl(host, MMCISTATUS);
8660c521ccbd0c9ad5623ff9b37b20b3ff9d4ad65a7Sahitya Tummala		status &= msmsdcc_readl(host, MMCIMASK0);
8674a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala		if ((status & (~MCI_IRQ_PIO)) == 0)
8684a268e0879c4044523757b6ac94b56fc7955a116Sahitya Tummala			break;
8698b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		msmsdcc_writel(host, status, MMCICLEAR);
8709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
871865c8064a2fb07100525097983966b8e789bde1aSan Mehat		if (status & MCI_SDIOINTR)
872865c8064a2fb07100525097983966b8e789bde1aSan Mehat			status &= ~MCI_SDIOINTR;
8739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
874865c8064a2fb07100525097983966b8e789bde1aSan Mehat		if (!status)
875865c8064a2fb07100525097983966b8e789bde1aSan Mehat			break;
8769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
877b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches		msmsdcc_handle_irq_data(host, status, base);
8789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
8799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (status & MCI_SDIOINTOPER) {
8809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			cardint = 1;
8819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			status &= ~MCI_SDIOINTOPER;
8829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		}
8839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ret = 1;
8849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} while (status);
8859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
8869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_unlock(&host->lock);
8879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
8889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	/*
8899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * We have to delay handling the card interrupt as it calls
8909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * back into the driver.
8919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 */
8929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (cardint)
8939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mmc_signal_sdio_irq(host->mmc);
8949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
8959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return IRQ_RETVAL(ret);
8969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
8979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
8989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
8999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
9009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
9019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host *host = mmc_priv(mmc);
9029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned long flags;
9039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	WARN_ON(host->curr.mrq != NULL);
9059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	WARN_ON(host->pwr == 0);
9069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_lock_irqsave(&host->lock, flags);
9089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->stats.reqs++;
9109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->eject) {
9129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
9139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mrq->cmd->error = 0;
9149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mrq->data->bytes_xfered = mrq->data->blksz *
9159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat						  mrq->data->blocks;
9169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		} else
9179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mrq->cmd->error = -ENOMEDIUM;
9189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		spin_unlock_irqrestore(&host->lock, flags);
9209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mmc_request_done(mmc, mrq);
9219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return;
9229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
9239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
924d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat	msmsdcc_enable_clocks(host);
9259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->curr.mrq = mrq;
9279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (mrq->data && mrq->data->flags & MMC_DATA_READ)
92956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		/* Queue/read data, daisy-chain command when data starts */
93056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
93156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	else
93256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat		msmsdcc_start_command(host, mrq->cmd, 0);
9339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->cmdpoll && !msmsdcc_spin_on_status(host,
9359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT,
9369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				CMD_SPINMAX)) {
9378b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		uint32_t status = msmsdcc_readl(host, MMCISTATUS);
9389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		msmsdcc_do_cmdirq(host, status);
9398b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		msmsdcc_writel(host,
9408b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat			       MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT,
9418b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat			       MMCICLEAR);
9429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->stats.cmdpoll_hits++;
9439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else {
9449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->stats.cmdpoll_misses++;
9459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
9469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_unlock_irqrestore(&host->lock, flags);
9479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
9489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
9497a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummalastatic void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
9507a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala{
9517a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	struct msm_mmc_gpio_data *curr;
9527a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	int i, rc = 0;
9537a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala
954435f3e385962e2b34855e9b34f8b95717c1016a2Alexander Tarasikov	if (!host->plat->gpio_data || host->gpio_config_status == enable)
9557a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala		return;
9567a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala
9577a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	curr = host->plat->gpio_data;
9587a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	for (i = 0; i < curr->size; i++) {
9597a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala		if (enable) {
9607a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala			rc = gpio_request(curr->gpio[i].no,
9617a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala						curr->gpio[i].name);
9627a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala			if (rc) {
9637a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala				pr_err("%s: gpio_request(%d, %s) failed %d\n",
9647a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala					mmc_hostname(host->mmc),
9657a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala					curr->gpio[i].no,
9667a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala					curr->gpio[i].name, rc);
9677a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala				goto free_gpios;
9687a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala			}
9697a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala		} else {
9707a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala			gpio_free(curr->gpio[i].no);
9717a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala		}
9727a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	}
9737a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	host->gpio_config_status = enable;
9747a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	return;
9757a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala
9767a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummalafree_gpios:
9777a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	for (; i >= 0; i--)
9787a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala		gpio_free(curr->gpio[i].no);
9797a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala}
9807a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala
9819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
9829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
9839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
9849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host *host = mmc_priv(mmc);
9859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	u32 clk = 0, pwr = 0;
9869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	int rc;
9874adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat	unsigned long flags;
9889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
989c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	spin_lock_irqsave(&host->lock, flags);
9909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
991d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat	msmsdcc_enable_clocks(host);
992d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat
9937a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	spin_unlock_irqrestore(&host->lock, flags);
9947a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala
995865c8064a2fb07100525097983966b8e789bde1aSan Mehat	if (ios->clock) {
9969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (ios->clock != host->clk_rate) {
9979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			rc = clk_set_rate(host->clk, ios->clock);
9989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			if (rc < 0)
9990a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches				pr_err("%s: Error setting clock rate (%d)\n",
10000a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches				       mmc_hostname(host->mmc), rc);
10019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			else
10029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				host->clk_rate = ios->clock;
10039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		}
10049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		clk |= MCI_CLK_ENABLE;
10059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
10069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (ios->bus_width == MMC_BUS_WIDTH_4)
10089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		clk |= (2 << 10); /* Set WIDEBUS */
10099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (ios->clock > 400000 && msmsdcc_pwrsave)
10119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		clk |= (1 << 9); /* PWRSAVE */
10129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	clk |= (1 << 12); /* FLOW_ENA */
10149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	clk |= (1 << 15); /* feedback clock */
10159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->plat->translate_vdd)
10179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
10189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	switch (ios->power_mode) {
10209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	case MMC_POWER_OFF:
10217a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala		msmsdcc_setup_gpio(host, false);
10229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		break;
10239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	case MMC_POWER_UP:
10249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		pwr |= MCI_PWR_UP;
10257a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala		msmsdcc_setup_gpio(host, true);
10269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		break;
10279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	case MMC_POWER_ON:
10289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		pwr |= MCI_PWR_ON;
10299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		break;
10309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
10319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
10339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		pwr |= MCI_OD;
10349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10358b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	msmsdcc_writel(host, clk, MMCICLOCK);
10369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->pwr != pwr) {
10389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->pwr = pwr;
10398b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		msmsdcc_writel(host, pwr, MMCIPOWER);
10409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
1041f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat#if BUSCLK_PWRSAVE
10427a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala	spin_lock_irqsave(&host->lock, flags);
1043c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	msmsdcc_disable_clocks(host, 1);
10444adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat	spin_unlock_irqrestore(&host->lock, flags);
10457a89248a47d201e6ade2daddd79b0fd902cad400Sahitya Tummala#endif
10469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
10479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
10499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
10509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host *host = mmc_priv(mmc);
10519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned long flags;
10529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	u32 status;
10539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_lock_irqsave(&host->lock, flags);
10559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (msmsdcc_sdioirq == 1) {
10568b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		status = msmsdcc_readl(host, MMCIMASK0);
10579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (enable)
10589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			status |= MCI_SDIOINTOPERMASK;
10599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		else
10609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			status &= ~MCI_SDIOINTOPERMASK;
10619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->saved_irq0mask = status;
10628b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		msmsdcc_writel(host, status, MMCIMASK0);
10639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
10649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_unlock_irqrestore(&host->lock, flags);
10659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
10669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1067e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikovstatic void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card)
1068e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov{
1069e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov	struct msmsdcc_host *host = mmc_priv(mmc);
1070e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov
1071e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov	if (host->plat->init_card)
1072e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov		host->plat->init_card(card);
1073e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov}
1074e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov
10759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic const struct mmc_host_ops msmsdcc_ops = {
10769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	.request	= msmsdcc_request,
10779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	.set_ios	= msmsdcc_set_ios,
10789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	.enable_sdio_irq = msmsdcc_enable_sdio_irq,
1079e91957e70d2aea529ff2055b8fbd575f2d7b8c3bAlexander Tarasikov	.init_card	= msmsdcc_init_card,
10809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat};
10819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
10839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_check_status(unsigned long data)
10849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
10859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host *host = (struct msmsdcc_host *)data;
10869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	unsigned int status;
10879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!host->plat->status) {
10899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mmc_detect_change(host->mmc, 0);
10909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		goto out;
10919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
10929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
10939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	status = host->plat->status(mmc_dev(host->mmc));
10949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->eject = !status;
10959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (status ^ host->oldstat) {
10960a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_info("%s: Slot status change detected (%d -> %d)\n",
10970a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			mmc_hostname(host->mmc), host->oldstat, status);
10989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (status)
10999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mmc_detect_change(host->mmc, (5 * HZ) / 2);
11009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		else
11019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mmc_detect_change(host->mmc, 0);
11029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
11039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->oldstat = status;
11059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout:
11079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->timer.function)
11089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mod_timer(&host->timer, jiffies + HZ);
11099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
11109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t
11129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_platform_status_irq(int irq, void *dev_id)
11139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
11149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host *host = dev_id;
11159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1116a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S	pr_debug("%s: %d\n", __func__, irq);
11179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	msmsdcc_check_status((unsigned long) host);
11189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return IRQ_HANDLED;
11199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
11209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
11229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_status_notify_cb(int card_present, void *dev_id)
11239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
11249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host *host = dev_id;
11259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1126a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S	pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
11279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	       card_present);
11289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	msmsdcc_check_status((unsigned long) host);
11299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
11309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void
1132865c8064a2fb07100525097983966b8e789bde1aSan Mehatmsmsdcc_busclk_expired(unsigned long _data)
11339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
11349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host	*host = (struct msmsdcc_host *) _data;
11359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1136865c8064a2fb07100525097983966b8e789bde1aSan Mehat	if (host->clks_on)
1137c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat		msmsdcc_disable_clocks(host, 0);
11389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
11399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int
11419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_init_dma(struct msmsdcc_host *host)
11429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
11439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
11449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.host = host;
11459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.channel = -1;
11469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!host->dmares)
11489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -ENODEV;
11499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.nc = dma_alloc_coherent(NULL,
11519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat					  sizeof(struct msmsdcc_nc_dmadata),
11529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat					  &host->dma.nc_busaddr,
11539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat					  GFP_KERNEL);
11549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->dma.nc == NULL) {
11550a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("Unable to allocate DMA buffer\n");
11569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -ENOMEM;
11579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
11589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
11599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.cmd_busaddr = host->dma.nc_busaddr;
11609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
11619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				offsetof(struct msmsdcc_nc_dmadata, cmdptr);
11629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dma.channel = host->dmares->start;
11639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return 0;
11659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
11669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int
11689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_probe(struct platform_device *pdev)
11699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
1170b5d643de3ea28d7844a3a1a00a0a6f50897a2a6bSahitya Tummala	struct msm_mmc_platform_data *plat = pdev->dev.platform_data;
11719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct msmsdcc_host *host;
11729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct mmc_host *mmc;
11739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct resource *cmd_irqres = NULL;
11749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct resource *stat_irqres = NULL;
11759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct resource *memres = NULL;
11769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct resource *dmares = NULL;
11779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	int ret;
11789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	/* must have platform data */
11809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!plat) {
11810a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Platform data not available\n", __func__);
11829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ret = -EINVAL;
11839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		goto out;
11849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
11859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (pdev->id < 1 || pdev->id > 4)
11879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -EINVAL;
11889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (pdev->resource == NULL || pdev->num_resources < 2) {
11900a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Invalid resource\n", __func__);
11919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -ENXIO;
11929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
11939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
11949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
11959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
11969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
11979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat						  "cmd_irq");
11989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
11999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat						   "status_irq");
12009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12014a92fe80becbbee650cfad8457ad0e5cd97ed974Sahitya Tummala	if (!cmd_irqres || !memres) {
12020a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Invalid resource\n", __func__);
12039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		return -ENXIO;
12049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
12059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	/*
12079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * Setup our host structure
12089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 */
12099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
12119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!mmc) {
12129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ret = -ENOMEM;
12139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		goto out;
12149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
12159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host = mmc_priv(mmc);
12179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->pdev_id = pdev->id;
12189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->plat = plat;
12199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->mmc = mmc;
122056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat	host->curr.cmd = NULL;
122119207f056d6dd390f96749e643a222d48517f7b1Sahitya Tummala	init_timer(&host->busclk_timer);
122219207f056d6dd390f96749e643a222d48517f7b1Sahitya Tummala	host->busclk_timer.data = (unsigned long) host;
122319207f056d6dd390f96749e643a222d48517f7b1Sahitya Tummala	host->busclk_timer.function = msmsdcc_busclk_expired;
122419207f056d6dd390f96749e643a222d48517f7b1Sahitya Tummala
12259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->cmdpoll = 1;
12279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->base = ioremap(memres->start, PAGE_SIZE);
12299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (!host->base) {
12309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ret = -ENOMEM;
1231dce7c756c84160424b3aea5ec36f221946bdc6f7Sahitya Tummala		goto host_free;
12329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
12339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->cmd_irqres = cmd_irqres;
12359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->memres = memres;
12369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->dmares = dmares;
12379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	spin_lock_init(&host->lock);
12389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
123962612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala	tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
124062612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala			(unsigned long)host);
124162612cf9d97068dc75b48a7a3044ee907a3283ecSahitya Tummala
12429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	/*
12439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * Setup DMA
12449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 */
1245190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani	if (host->dmares) {
1246190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani		ret = msmsdcc_init_dma(host);
1247190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani		if (ret)
1248190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani			goto ioremap_free;
1249190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani	} else {
1250190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani		host->dma.channel = -1;
1251190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani	}
12529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12534adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat	/* Get our clocks */
12549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->pclk = clk_get(&pdev->dev, "sdc_pclk");
12559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (IS_ERR(host->pclk)) {
12569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ret = PTR_ERR(host->pclk);
1257dce7c756c84160424b3aea5ec36f221946bdc6f7Sahitya Tummala		goto dma_free;
12589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
12599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->clk = clk_get(&pdev->dev, "sdc_clk");
12619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (IS_ERR(host->clk)) {
12629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ret = PTR_ERR(host->clk);
12634adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat		goto pclk_put;
12649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
12659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	ret = clk_set_rate(host->clk, msmsdcc_fmin);
12679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (ret) {
12680a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
1269514d9eda92654430369060b91f7472bb198e7904Sahitya Tummala		goto clk_put;
12709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
12719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1272514d9eda92654430369060b91f7472bb198e7904Sahitya Tummala	/* Enable clocks */
1273514d9eda92654430369060b91f7472bb198e7904Sahitya Tummala	ret = msmsdcc_enable_clocks(host);
1274514d9eda92654430369060b91f7472bb198e7904Sahitya Tummala	if (ret)
1275514d9eda92654430369060b91f7472bb198e7904Sahitya Tummala		goto clk_put;
1276514d9eda92654430369060b91f7472bb198e7904Sahitya Tummala
12774adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat	host->pclk_rate = clk_get_rate(host->pclk);
12789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->clk_rate = clk_get_rate(host->clk);
12799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	/*
12819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * Setup MMC host structure
12829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 */
12839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->ops = &msmsdcc_ops;
12849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->f_min = msmsdcc_fmin;
12859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->f_max = msmsdcc_fmax;
12869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->ocr_avail = plat->ocr_mask;
12879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (msmsdcc_4bit)
12899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mmc->caps |= MMC_CAP_4_BIT_DATA;
12909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (msmsdcc_sdioirq)
12919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		mmc->caps |= MMC_CAP_SDIO_IRQ;
12929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
12939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1294a36274e0184193e393fb82957925c3981a6b0477Martin K. Petersen	mmc->max_segs = NR_SG;
12959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->max_blk_size = 4096;	/* MCI_DATA_CTL BLOCKSIZE up to 4096 */
12969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->max_blk_count = 65536;
12979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
12989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->max_req_size = 33554432;	/* MCI_DATA_LENGTH is 25 bits */
12999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc->max_seg_size = mmc->max_req_size;
13009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13018b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	msmsdcc_writel(host, 0, MMCIMASK0);
13028b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	msmsdcc_writel(host, 0x5e007ff, MMCICLEAR);
13039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13048b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat	msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
13059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	host->saved_irq0mask = MCI_IRQENABLE;
13069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	/*
13089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 * Setup card detect change
13099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	 */
13109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	memset(&host->timer, 0, sizeof(host->timer));
13129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) {
13149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		unsigned long irqflags = IRQF_SHARED |
13159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			(stat_irqres->flags & IRQF_TRIGGER_MASK);
13169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->stat_irq = stat_irqres->start;
13189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		ret = request_irq(host->stat_irq,
13199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				  msmsdcc_platform_status_irq,
13209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				  irqflags,
13219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				  DRIVER_NAME " (slot)",
13229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat				  host);
13239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (ret) {
13240a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			pr_err("%s: Unable to get slot IRQ %d (%d)\n",
13250a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			       mmc_hostname(mmc), host->stat_irq, ret);
13269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			goto clk_disable;
13279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		}
13289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else if (plat->register_status_notify) {
13299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		plat->register_status_notify(msmsdcc_status_notify_cb, host);
13309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else if (!plat->status)
13310a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_err("%s: No card detect facilities available\n",
13329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		       mmc_hostname(mmc));
13339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	else {
13349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		init_timer(&host->timer);
13359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->timer.data = (unsigned long)host;
13369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->timer.function = msmsdcc_check_status;
13379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->timer.expires = jiffies + HZ;
13389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		add_timer(&host->timer);
13399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
13409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (plat->status) {
13429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->oldstat = host->plat->status(mmc_dev(host->mmc));
13439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		host->eject = !host->oldstat;
13449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
13459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
13479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			  DRIVER_NAME " (cmd)", host);
13489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (ret)
13499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		goto stat_irq_free;
13509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13514a92fe80becbbee650cfad8457ad0e5cd97ed974Sahitya Tummala	ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
13529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			  DRIVER_NAME " (pio)", host);
13539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (ret)
13549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		goto cmd_irq_free;
13559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc_set_drvdata(pdev, mmc);
13579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc_add_host(mmc);
13589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13590a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches	pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
13600a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		mmc_hostname(mmc), (unsigned long long)memres->start,
13610a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		(unsigned int) cmd_irqres->start,
13620a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		(unsigned int) host->stat_irq, host->dma.channel);
13630a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches	pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
13640a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		(mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
13650a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches	pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
13660a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate);
13670a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches	pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject);
13680a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches	pr_info("%s: Power save feature enable = %d\n",
13690a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		mmc_hostname(mmc), msmsdcc_pwrsave);
13709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->dma.channel != -1) {
13720a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
13730a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
13740a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
13750a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			mmc_hostname(mmc), host->dma.cmd_busaddr,
13760a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches			host->dma.cmdptr_busaddr);
13779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	} else
13780a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
13799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->timer.function)
13800a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches		pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
13819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
13829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return 0;
13839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd_irq_free:
13849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	free_irq(cmd_irqres->start, host);
13859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat stat_irq_free:
13869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (host->stat_irq)
13879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		free_irq(host->stat_irq, host);
13889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_disable:
1389c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat	msmsdcc_disable_clocks(host, 0);
13909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put:
13919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	clk_put(host->clk);
13929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pclk_put:
13939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	clk_put(host->pclk);
1394dce7c756c84160424b3aea5ec36f221946bdc6f7Sahitya Tummaladma_free:
1395190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani	if (host->dmares)
1396190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani		dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata),
1397190657c9f464b9f99a05a6ed8476c8bbccbc6a8bSubhash Jadavani					host->dma.nc, host->dma.nc_busaddr);
1398dce7c756c84160424b3aea5ec36f221946bdc6f7Sahitya Tummalaioremap_free:
1399dce7c756c84160424b3aea5ec36f221946bdc6f7Sahitya Tummala	tasklet_kill(&host->dma_tlet);
1400dce7c756c84160424b3aea5ec36f221946bdc6f7Sahitya Tummala	iounmap(host->base);
14019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host_free:
14029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	mmc_free_host(mmc);
14039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat out:
14049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return ret;
14059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
14069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
140708ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker#ifdef CONFIG_PM
140808ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ
140908ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walkerstatic void
141008ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walkerdo_resume_work(struct work_struct *work)
141108ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker{
141208ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker	struct msmsdcc_host *host =
141308ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker		container_of(work, struct msmsdcc_host, resume_task);
141408ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker	struct mmc_host	*mmc = host->mmc;
141508ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker
141608ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker	if (mmc) {
141708ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker		mmc_resume_host(mmc);
141808ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker		if (host->stat_irq)
141908ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker			enable_irq(host->stat_irq);
142008ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker	}
142108ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker}
142208ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker#endif
142308ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker
142408ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker
14259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int
14269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_suspend(struct platform_device *dev, pm_message_t state)
14279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
14289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct mmc_host *mmc = mmc_get_drvdata(dev);
14299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	int rc = 0;
14309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (mmc) {
14329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		struct msmsdcc_host *host = mmc_priv(mmc);
14339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (host->stat_irq)
14359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			disable_irq(host->stat_irq);
14369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
14381a13f8fa76c880be41d6b1e6a2b44404bcbfdf9eMatt Fleming			rc = mmc_suspend_host(mmc);
1439d0719e59f4ad96616f7c02ef0201667e41778c88San Mehat		if (!rc)
14408b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat			msmsdcc_writel(host, 0, MMCIMASK0);
1441c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat		if (host->clks_on)
1442c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat			msmsdcc_disable_clocks(host, 0);
14439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
14449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return rc;
14459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
14469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int
14489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_resume(struct platform_device *dev)
14499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{
14509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	struct mmc_host *mmc = mmc_get_drvdata(dev);
14519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	if (mmc) {
14539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		struct msmsdcc_host *host = mmc_priv(mmc);
14549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1455c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat		msmsdcc_enable_clocks(host);
14569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14578b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat		msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
14589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
14609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			mmc_resume_host(mmc);
14615b8a2fb34f5670b1f07483bfa40de9ce539dbdb2Roel Kluin		if (host->stat_irq)
14629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat			enable_irq(host->stat_irq);
1463f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat#if BUSCLK_PWRSAVE
1464c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat		msmsdcc_disable_clocks(host, 1);
1465f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5San Mehat#endif
14669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	}
14679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	return 0;
14689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}
146908ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker#else
147008ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker#define msmsdcc_suspend	0
147108ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker#define msmsdcc_resume 0
147208ecfde47534ced67c3c16a15845456e83bd31d1Daniel Walker#endif
14739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic struct platform_driver msmsdcc_driver = {
14759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	.probe		= msmsdcc_probe,
14769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	.suspend	= msmsdcc_suspend,
14779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	.resume		= msmsdcc_resume,
14789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	.driver		= {
14799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat		.name	= "msm_sdcc",
14809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat	},
14819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat};
14829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
1483d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(msmsdcc_driver);
14849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat
14859d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver");
14869d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_LICENSE("GPL");
1487