msm_sdcc.c revision 190657c9f464b9f99a05a6ed8476c8bbccbc6a8b
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) { 392208028de5fa7732704d12cdd3f8fd45d2d8445e3Daniel Walker printk(KERN_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) { 47856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat printk(KERN_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); 6929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat buffer = kmap_atomic(sg_page(host->pio.sg), 6939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat KM_BIO_SRC_IRQ) + 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 */ 7039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat kunmap_atomic(buffer, KM_BIO_SRC_IRQ); 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 11169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_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 11269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_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 14839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int __init msmsdcc_init(void) 14849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 14859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return platform_driver_register(&msmsdcc_driver); 14869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 14879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 14889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void __exit msmsdcc_exit(void) 14899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 14909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat platform_driver_unregister(&msmsdcc_driver); 14919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 14929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 14939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_init(msmsdcc_init); 14949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_exit(msmsdcc_exit); 14959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 14969d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); 14979d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_LICENSE("GPL"); 1498