msm_sdcc.c revision c7fc9370df1433486dfa9460a833fae664e8be6c
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> 389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/cacheflush.h> 409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/div64.h> 419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <asm/sizes.h> 429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 433989d17847071fa94c93299805a9cca27cf65d26Pavel Machek#include <mach/mmc.h> 449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <mach/msm_iomap.h> 459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include <mach/dma.h> 469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#include "msm_sdcc.h" 489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define DRIVER_NAME "msm-sdcc" 509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 51c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat#define BUSCLK_TIMEOUT (HZ) 529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_fmin = 144000; 539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_fmax = 50000000; 549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_4bit = 1; 559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_pwrsave = 1; 569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_piopoll = 1; 579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic unsigned int msmsdcc_sdioirq; 589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define PIO_SPINMAX 30 609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#define CMD_SPINMAX 20 619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 62865c8064a2fb07100525097983966b8e789bde1aSan Mehat 63c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehatstatic inline void 64c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehatmsmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) 65865c8064a2fb07100525097983966b8e789bde1aSan Mehat{ 66c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat WARN_ON(!host->clks_on); 678b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat 68c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat if (deferr) { 69c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); 70865c8064a2fb07100525097983966b8e789bde1aSan Mehat } else { 71c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat del_timer_sync(&host->busclk_timer); 72c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat// dev_info(mmc_dev(host->mmc), "Immediate clock shutdown\n"); 73865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->clk); 74865c8064a2fb07100525097983966b8e789bde1aSan Mehat clk_disable(host->pclk); 75865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->clks_on = 0; 76865c8064a2fb07100525097983966b8e789bde1aSan Mehat } 77c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat} 78c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat 79c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehatstatic inline int 80c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehatmsmsdcc_enable_clocks(struct msmsdcc_host *host) 81c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat{ 82c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat int rc; 83c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat 84c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat WARN_ON(host->clks_on); 85c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat 86c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat del_timer_sync(&host->busclk_timer); 87c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat 88c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat rc = clk_enable(host->pclk); 89c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat if (rc) 90c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat return rc; 91c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat rc = clk_enable(host->clk); 92c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat if (rc) { 93c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat clk_disable(host->pclk); 94c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat return rc; 95c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat } 96c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat udelay(1 + ((3 * USEC_PER_SEC) / 97c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); 98c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat host->clks_on = 1; 99865c8064a2fb07100525097983966b8e789bde1aSan Mehat return 0; 100865c8064a2fb07100525097983966b8e789bde1aSan Mehat} 101865c8064a2fb07100525097983966b8e789bde1aSan Mehat 1028b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatstatic inline unsigned int 1038b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatmsmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) 1048b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat{ 1058b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat return readl(host->base + reg); 1068b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat} 1078b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat 1088b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatstatic inline void 1098b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehatmsmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) 1108b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat{ 1118b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat writel(data, host->base + reg); 1128b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat /* 3 clk delay required! */ 1138b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat udelay(1 + ((3 * USEC_PER_SEC) / 1148b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); 1158b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat} 116865c8064a2fb07100525097983966b8e789bde1aSan Mehat 1179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, 1199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 c); 1209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) 1239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(host->curr.data); 1259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 1279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 1289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data) 1309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = host->curr.data_xfered; 1319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->cmd->error == -ETIMEDOUT) 1329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mdelay(5); 1339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 134c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 1); 1359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 1369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Need to drop the host lock here; mmc_request_done may call 1379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * back into the driver... 1389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 1399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock(&host->lock); 1409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 1419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock(&host->lock); 1429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_stop_data(struct msmsdcc_host *host) 1469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data = NULL; 1489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_dataend = host->curr.got_datablkend = 0; 1499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatuint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) 1529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 15375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches switch (host->pdev_id) { 15475d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 1: 1559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC1_PHYS + MMCIFIFO; 15675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 2: 1579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC2_PHYS + MMCIFIFO; 15875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 3: 1599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC3_PHYS + MMCIFIFO; 16075d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 4: 1619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return MSM_SDC4_PHYS + MMCIFIFO; 16275d145283b2e42619d7ee1e00b78466bacd51808Joe Perches } 16375d145283b2e42619d7ee1e00b78466bacd51808Joe Perches BUG(); 1649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 1659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 1669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 16756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic inline void 16856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { 16956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_writel(host, arg, MMCIARGUMENT); 17056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_writel(host, c, MMCICOMMAND); 17156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat} 17256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 17356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic void 17456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) 17556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat{ 17656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; 17756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 17856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat writel(host->cmd_timeout, host->base + MMCIDATATIMER); 17956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat writel((unsigned int)host->curr.xfer_size, host->base + MMCIDATALENGTH); 18056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat writel(host->cmd_pio_irqmask, host->base + MMCIMASK1); 18156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat writel(host->cmd_datactrl, host->base + MMCIDATACTRL); 18256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 18356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (host->cmd_cmd) { 18456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_command_exec(host, 18556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat (u32)host->cmd_cmd->arg, (u32)host->cmd_c); 18656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 18756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.active = 1; 18856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat} 18956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 1909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 1919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, 1929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int result, 1939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msm_dmov_errdata *err) 1949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 1959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_dma_data *dma_data = 1969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat container_of(cmd, struct msmsdcc_dma_data, hdr); 1979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dma_data->host; 1989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 1999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_request *mrq; 2009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 20256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.active = 0; 20356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 2049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq = host->curr.mrq; 2059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(!mrq); 2069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!(result & DMOV_RSLT_VALID)) { 2080a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("msmsdcc: Invalid DataMover result\n"); 2099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 2109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_DONE) { 2139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = host->curr.xfer_size; 2149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 2159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Error or flush */ 2169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_ERROR) 2170a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: DMA error (0x%.8x)\n", 2189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc), result); 2199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (result & DMOV_RSLT_FLUSH) 2200a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: DMA channel flushed (0x%.8x)\n", 2219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(host->mmc), result); 2229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (err) 2230a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", 2249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat err->flush[0], err->flush[1], err->flush[2], 2259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat err->flush[3], err->flush[4], err->flush[5]); 2269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->error) 2279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->error = -EIO; 2289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, 2309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir); 2319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.user_pages) { 2339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct scatterlist *sg = host->dma.sg; 2349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int i; 2359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 23675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches for (i = 0; i < host->dma.num_ents; i++) 23775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches flush_dcache_page(sg_page(sg++)); 2389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 24156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.busy = 0; 2429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((host->curr.got_dataend && host->curr.got_datablkend) 2449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat || mrq->data->error) { 2459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 2479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * If we've already gotten our DATAEND / DATABLKEND 2489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * for this request, then complete it through here. 2499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 2509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 2519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->error) 2539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = host->curr.xfer_size; 2549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mrq->data->stop || mrq->cmd->error) { 2559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = NULL; 2569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 2579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = host->curr.data_xfered; 2589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 260c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 1); 2619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(host->mmc, mrq); 2629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 2639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 2649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_start_command(host, mrq->data->stop, 0); 2659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 2669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout: 2689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 2699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 2709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 2719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) 2739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 2749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.channel == -1) 2759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOENT; 2769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((data->blksz * data->blocks) < MCI_FIFOSIZE) 2789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 2799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if ((data->blksz * data->blocks) % MCI_FIFOSIZE) 2809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 2819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 2829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 2839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) 2859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 2869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_nc_dmadata *nc; 2879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dmov_box *box; 2889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t rows; 2899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t crci; 2909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int n; 2919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int i, rc; 2929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct scatterlist *sg = data->sg; 2939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = validate_dma(host, data); 2959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (rc) 2969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return rc; 2979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 2989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = data->sg; 2999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = data->sg_len; 3009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 30156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ 30256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 3039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat nc = host->dma.nc; 3049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 30575d145283b2e42619d7ee1e00b78466bacd51808Joe Perches switch (host->pdev_id) { 30675d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 1: 3079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC1; 30875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 30975d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 2: 3109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC2; 31175d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 31275d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 3: 3139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC3; 31475d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 31575d145283b2e42619d7ee1e00b78466bacd51808Joe Perches case 4: 3169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat crci = MSMSDCC_CRCI_SDC4; 31775d145283b2e42619d7ee1e00b78466bacd51808Joe Perches break; 31875d145283b2e42619d7ee1e00b78466bacd51808Joe Perches default: 3199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.sg = NULL; 3209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.num_ents = 0; 3219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOENT; 3229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) 3259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir = DMA_FROM_DEVICE; 3269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 3279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.dir = DMA_TO_DEVICE; 3289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.user_pages = 0; 3309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box = &nc->cmd[0]; 3329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat for (i = 0; i < host->dma.num_ents; i++) { 3339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd = CMD_MODE_BOX; 3349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 33556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat /* Initialize sg dma address */ 33656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) 33756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat + sg->offset; 33856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 33956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (i == (host->dma.num_ents - 1)) 3409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_LC; 3419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? 3429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : 3439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (sg_dma_len(sg) / MCI_FIFOSIZE) ; 3449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) { 3469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_row_addr = msmsdcc_fifo_addr(host); 3479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->dst_row_addr = sg_dma_address(sg); 3489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_dst_len = (MCI_FIFOSIZE << 16) | 3509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_FIFOSIZE); 3519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->row_offset = MCI_FIFOSIZE; 3529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->num_rows = rows * ((1 << 16) + 1); 3549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_SRC_CRCI(crci); 3559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 3569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_row_addr = sg_dma_address(sg); 3579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->dst_row_addr = msmsdcc_fifo_addr(host); 3589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->src_dst_len = (MCI_FIFOSIZE << 16) | 3609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_FIFOSIZE); 3619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->row_offset = (MCI_FIFOSIZE << 16); 3629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->num_rows = rows * ((1 << 16) + 1); 3649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box->cmd |= CMD_DST_CRCI(crci); 3659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat box++; 3679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat sg++; 3689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 3699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* location of command block must be 64 bit aligned */ 3719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat BUG_ON(host->dma.cmd_busaddr & 0x07); 3729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 3739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; 3749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | 3759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); 3769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.hdr.complete_func = msmsdcc_dma_complete_func; 3779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 37856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, 37956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.num_ents, host->dma.dir); 38056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat/* dsb inside dma_map_sg will write nc out to mem as well */ 38156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 38256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (n != host->dma.num_ents) { 38356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat printk(KERN_ERR "%s: Unable to map in all sg elements\n", 38456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat mmc_hostname(host->mmc)); 38556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.sg = NULL; 38656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.num_ents = 0; 38756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat return -ENOMEM; 38856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 38956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 39056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat return 0; 39156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat} 39256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 39356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic int 39456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatsnoop_cccr_abort(struct mmc_command *cmd) 39556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat{ 39656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if ((cmd->opcode == 52) && 39756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat (cmd->arg & 0x80000000) && 39856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) 39956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat return 1; 4009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 4019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 4029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 40456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_start_command_deferred(struct msmsdcc_host *host, 40556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat struct mmc_command *cmd, u32 *c) 40656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat{ 40756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *c |= (cmd->opcode | MCI_CPSM_ENABLE); 40856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 40956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (cmd->flags & MMC_RSP_PRESENT) { 41056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (cmd->flags & MMC_RSP_136) 41156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *c |= MCI_CPSM_LONGRSP; 41256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *c |= MCI_CPSM_RESPONSE; 41356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 41456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 41556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (/*interrupt*/0) 41656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *c |= MCI_CPSM_INTERRUPT; 41756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 41856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || 41956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat ((cmd->opcode == 24) || (cmd->opcode == 25))) || 42056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat (cmd->opcode == 53)) 42156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *c |= MCI_CSPM_DATCMD; 42256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 42356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (cmd == cmd->mrq->stop) 42456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *c |= MCI_CSPM_MCIABORT; 42556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 42656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (snoop_cccr_abort(cmd)) 42756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat *c |= MCI_CSPM_MCIABORT; 42856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 42956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (host->curr.cmd != NULL) { 43056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat printk(KERN_ERR "%s: Overlapping command requests\n", 43156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat mmc_hostname(host->mmc)); 43256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 43356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->curr.cmd = cmd; 43456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat} 43556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 43656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatstatic void 43756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehatmsmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, 43856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat struct mmc_command *cmd, u32 c) 4399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 4409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int datactrl, timeout; 4419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long long clks; 4429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int pio_irqmask = 0; 4439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data = data; 4459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_size = data->blksz * data->blocks; 4469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_remain = host->curr.xfer_size; 4479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered = 0; 4489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_dataend = 0; 4499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.got_datablkend = 0; 4509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->pio, 0, sizeof(host->pio)); 4529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); 4549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!msmsdcc_config_dma(host, data)) 4569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl |= MCI_DPSM_DMAENABLE; 4579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else { 4589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg = data->sg; 4599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_len = data->sg_len; 4609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off = 0; 4619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) { 4639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask = MCI_RXFIFOHALFFULLMASK; 4649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.xfer_remain < MCI_FIFOSIZE) 4659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask |= MCI_RXDATAAVLBLMASK; 4669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 4679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqmask = MCI_TXFIFOHALFEMPTYMASK; 4689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 4699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (data->flags & MMC_DATA_READ) 4719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat datactrl |= MCI_DPSM_DIRECTION; 4729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 47356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat clks = (unsigned long long)data->timeout_ns * host->clk_rate; 47456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat do_div(clks, NSEC_PER_SEC); 47556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat timeout = data->timeout_clks + (unsigned int)clks*2 ; 4769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 4779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (datactrl & MCI_DPSM_DMAENABLE) { 47856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat /* Save parameters for the exec function */ 47956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->cmd_timeout = timeout; 48056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->cmd_pio_irqmask = pio_irqmask; 48156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->cmd_datactrl = datactrl; 48256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->cmd_cmd = cmd; 48356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 48456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.hdr.execute_func = msmsdcc_dma_exec_func; 48556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->dma.hdr.data = (void *)host; 4869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.busy = 1; 48756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 48856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (cmd) { 48956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_command_deferred(host, cmd, &c); 49056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->cmd_c = c; 49156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 4929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); 49356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } else { 49456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_writel(host, timeout, MMCIDATATIMER); 4959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 49656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); 49756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 49856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_writel(host, pio_irqmask, MMCIMASK1); 49956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_writel(host, datactrl, MMCIDATACTRL); 50056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 50156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (cmd) { 50256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat /* Daisy-chain the command if requested */ 50356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_command(host, cmd, c); 50456a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 50556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 506b3fa579118b239e218e690f5ef76870aff6fe738San Mehat} 507b3fa579118b239e218e690f5ef76870aff6fe738San Mehat 5089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 5099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) 5109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cmd == cmd->mrq->stop) 5129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat c |= MCI_CSPM_MCIABORT; 5139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmds++; 5159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 51656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_command_deferred(host, cmd, &c); 51756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_command_exec(host, cmd->arg, c); 5189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 5219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, 5229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int status) 5239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_DATACRCFAIL) { 5250a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc)); 5260a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: opcode 0x%.8x\n", __func__, 5279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->mrq->cmd->opcode); 5280a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: blksz %d, blocks %d\n", __func__, 5299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->blksz, data->blocks); 5309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EILSEQ; 5319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_DATATIMEOUT) { 5320a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Data timeout\n", mmc_hostname(host->mmc)); 5339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -ETIMEDOUT; 5349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_RXOVERRUN) { 5350a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: RX overrun\n", mmc_hostname(host->mmc)); 5369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 5379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_TXUNDERRUN) { 5380a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: TX underrun\n", mmc_hostname(host->mmc)); 5399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 5409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 5410a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unknown error (0x%.8x)\n", 5420a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), status); 5439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat data->error = -EIO; 5449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 5499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) 5509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t *ptr = (uint32_t *) buffer; 5529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int count = 0; 5539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5548b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { 5558b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); 5569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ptr++; 5579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat count += sizeof(uint32_t); 5589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= sizeof(uint32_t); 5609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) 5619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 5639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return count; 5649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 5679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, 5689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int remain, u32 status) 5699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 5719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat char *ptr = buffer; 5729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 5749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int count, maxcnt; 5759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : 5779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_FIFOHALFSIZE; 5789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat count = min(remain, maxcnt); 5799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat writesl(base + MMCIFIFO, ptr, count >> 2); 5819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ptr += count; 5829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= count; 5839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) 5859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 5869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5878b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 5889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (status & MCI_TXFIFOHALFEMPTY); 5899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return ptr - buffer; 5919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 5929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 5939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 5949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) 5959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 5969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat while (maxspin) { 5978b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat if ((msmsdcc_readl(host, MMCISTATUS) & mask)) 5989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 5999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat udelay(1); 6009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat --maxspin; 6019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ETIMEDOUT; 6039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 6049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 6069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_pio_irq(int irq, void *dev_id) 6079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 6089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 6099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat uint32_t status; 6109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6118b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 6129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 6149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 6159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int remain, len; 6169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat char *buffer; 6179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { 6199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) 6209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 6219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_spin_on_status(host, 6239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (MCI_TXFIFOHALFEMPTY | 6249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_RXDATAAVLBL), 6259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat PIO_SPINMAX)) { 6269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 6279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Map the current scatter buffer */ 6319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat local_irq_save(flags); 6329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat buffer = kmap_atomic(sg_page(host->pio.sg), 6339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat KM_BIO_SRC_IRQ) + host->pio.sg->offset; 6349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat buffer += host->pio.sg_off; 6359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain = host->pio.sg->length - host->pio.sg_off; 6369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = 0; 6379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE) 6389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = msmsdcc_pio_read(host, buffer, remain); 6399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_TXACTIVE) 6409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat len = msmsdcc_pio_write(host, buffer, remain, status); 6419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Unmap the buffer */ 6439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat kunmap_atomic(buffer, KM_BIO_SRC_IRQ); 6449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat local_irq_restore(flags); 6459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off += len; 6479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.xfer_remain -= len; 6489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.data_xfered += len; 6499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat remain -= len; 6509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (remain == 0) { 6529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* This sg page is full - do some housekeeping */ 6539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE && host->curr.user_pages) 6549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat flush_dcache_page(sg_page(host->pio.sg)); 6559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!--host->pio.sg_len) { 6579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->pio, 0, sizeof(host->pio)); 6589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 6599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* Advance to next sg */ 6629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg++; 6639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio.sg_off = 0; 6649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6668b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 6679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (1); 6689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) 6708b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); 6719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->curr.xfer_remain) 6738b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCIMASK1); 6749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_HANDLED; 6769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 6779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) 6799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 6809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_command *cmd = host->curr.cmd; 6819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.cmd = NULL; 6838b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); 6848b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); 6858b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); 6868b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); 6879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_CMDTIMEOUT) { 6899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->error = -ETIMEDOUT; 6909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (status & MCI_CMDCRCFAIL && 6919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->flags & MMC_RSP_CRC) { 6920a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); 6939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd->error = -EILSEQ; 6949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 6959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 6969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!cmd->data || cmd->error) { 6979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->curr.data && host->dma.sg) 6989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msm_dmov_stop_cmd(host->dma.channel, 6999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat &host->dma.hdr, 0); 7009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else if (host->curr.data) { /* Non DMA */ 7019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_stop_data(host); 7029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_request_end(host, cmd->mrq); 7039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else /* host->data == NULL */ 7049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_request_end(host, cmd->mrq); 70556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } else if (cmd->data) 70656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (!(cmd->data->flags & MMC_DATA_READ)) 70756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_data(host, cmd->data, 70856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat NULL, 0); 7099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 7109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 711b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesstatic void 712b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perchesmsmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, 713b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches void __iomem *base) 714b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches{ 71556a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat struct mmc_data *data; 716b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 71756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | 71856a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat MCI_CMDTIMEOUT) && host->curr.cmd) { 71956a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_do_cmdirq(host, status); 72056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat } 72156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 72256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat data = host->curr.data; 723b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data) 724b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches return; 725b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 726b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* Check for data errors */ 727b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | 728b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches MCI_TXUNDERRUN | MCI_RXOVERRUN)) { 729b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_data_err(host, data, status); 730b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.data_xfered = 0; 731b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (host->dma.sg) 732b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msm_dmov_stop_cmd(host->dma.channel, 733b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches &host->dma.hdr, 0); 734b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else { 735b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_stop_data(host); 736b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->stop) 737b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_request_end(host, data->mrq); 738b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else 739b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_start_command(host, data->stop, 0); 740b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 741b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 742b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 743b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* Check for data done */ 744b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!host->curr.got_dataend && (status & MCI_DATAEND)) 745b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.got_dataend = 1; 746b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 747b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND)) 748b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.got_datablkend = 1; 749b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 750b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* 751b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * If DMA is still in progress, we complete via the completion handler 752b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches */ 753b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (host->curr.got_dataend && host->curr.got_datablkend && 754b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches !host->dma.busy) { 755b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches /* 756b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * There appears to be an issue in the controller where 757b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * if you request a small block transfer (< fifo size), 758b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * you may get your DATAEND/DATABLKEND irq without the 759b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * PIO data irq. 760b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * 761b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * Check to see if there is still data to be read, 762b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches * and simulate a PIO irq. 763b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches */ 764b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) 765b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_pio_irq(1, host); 766b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 767b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_stop_data(host); 768b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->error) 769b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches host->curr.data_xfered = host->curr.xfer_size; 770b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 771b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches if (!data->stop) 772b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_request_end(host, data->mrq); 773b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches else 774b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_start_command(host, data->stop, 0); 775b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches } 776b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches} 777b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches 7789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t 7799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_irq(int irq, void *dev_id) 7809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 7819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 7829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat void __iomem *base = host->base; 7839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 status; 7849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int ret = 0; 7859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int cardint = 0; 7869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock(&host->lock); 7889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 7899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat do { 7908b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat struct mmc_data *data; 7918b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCISTATUS); 7928b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status &= (msmsdcc_readl(host, MMCIMASK0) | 7938b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat MCI_DATABLOCKENDMASK); 7948b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, status, MMCICLEAR); 7959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 796865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (status & MCI_SDIOINTR) 797865c8064a2fb07100525097983966b8e789bde1aSan Mehat status &= ~MCI_SDIOINTR; 798865c8064a2fb07100525097983966b8e789bde1aSan Mehat 799865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!status) 800865c8064a2fb07100525097983966b8e789bde1aSan Mehat break; 801865c8064a2fb07100525097983966b8e789bde1aSan Mehat 802b5a74d6058e86546868242bb5283e16fb10fd90aJoe Perches msmsdcc_handle_irq_data(host, status, base); 8039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status & MCI_SDIOINTOPER) { 8059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cardint = 1; 8069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status &= ~MCI_SDIOINTOPER; 8079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = 1; 8099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } while (status); 8109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock(&host->lock); 8129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 8149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * We have to delay handling the card interrupt as it calls 8159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * back into the driver. 8169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 8179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (cardint) 8189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_signal_sdio_irq(host->mmc); 8199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_RETVAL(ret); 8219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 8229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 8249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) 8259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 8269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 8279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 8289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat WARN_ON(host->curr.mrq != NULL); 8309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat WARN_ON(host->pwr == 0); 8319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 8339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.reqs++; 8359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->eject) { 8379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) { 8389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = 0; 8399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->bytes_xfered = mrq->data->blksz * 8409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->data->blocks; 8419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 8429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mrq->cmd->error = -ENOMEDIUM; 8439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 8459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_request_done(mmc, mrq); 8469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return; 8479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->curr.mrq = mrq; 850c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat 851c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat /* Need to drop the host lock here in case 852c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat * the busclk wd fires 853c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat */ 854c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat spin_unlock_irqrestore(&host->lock, flags); 855865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!host->clks_on) 856c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_enable_clocks(host); 857c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat spin_lock_irqsave(&host->lock, flags); 8589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mrq->data && mrq->data->flags & MMC_DATA_READ) 86056a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat /* Queue/read data, daisy-chain command when data starts */ 86156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); 86256a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat else 86356a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat msmsdcc_start_command(host, mrq->cmd, 0); 8649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->cmdpoll && !msmsdcc_spin_on_status(host, 8669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, 8679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat CMD_SPINMAX)) { 8688b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat uint32_t status = msmsdcc_readl(host, MMCISTATUS); 8699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_do_cmdirq(host, status); 8708b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 8718b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, 8728b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat MMCICLEAR); 8739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmdpoll_hits++; 8749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else { 8759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stats.cmdpoll_misses++; 8769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 8779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 8789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 8799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 8809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 8819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 8829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 8839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 8849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 clk = 0, pwr = 0; 8859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int rc; 8864adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat unsigned long flags; 8879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 888865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (!host->clks_on) 889c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_enable_clocks(host); 890c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat 891c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat spin_lock_irqsave(&host->lock, flags); 8929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 893865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (ios->clock) { 8949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->clock != host->clk_rate) { 8959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = clk_set_rate(host->clk, ios->clock); 8969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (rc < 0) 8970a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Error setting clock rate (%d)\n", 8980a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), rc); 8999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 9009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk_rate = ios->clock; 9019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= MCI_CLK_ENABLE; 9039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->bus_width == MMC_BUS_WIDTH_4) 9069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (2 << 10); /* Set WIDEBUS */ 9079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->clock > 400000 && msmsdcc_pwrsave) 9099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 9); /* PWRSAVE */ 9109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 12); /* FLOW_ENA */ 9129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk |= (1 << 15); /* feedback clock */ 9139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->plat->translate_vdd) 9159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); 9169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat switch (ios->power_mode) { 9189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_OFF: 9199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 9209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_UP: 9219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_PWR_UP; 9229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 9239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat case MMC_POWER_ON: 9249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_PWR_ON; 9259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat break; 9269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 9299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pwr |= MCI_OD; 9309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9318b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, clk, MMCICLOCK); 9329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->pwr != pwr) { 9349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pwr = pwr; 9358b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, pwr, MMCIPOWER); 9369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 937c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 1); 9384adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat spin_unlock_irqrestore(&host->lock, flags); 9399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) 9429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 9449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long flags; 9459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat u32 status; 9469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_irqsave(&host->lock, flags); 9489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_sdioirq == 1) { 9498b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat status = msmsdcc_readl(host, MMCIMASK0); 9509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (enable) 9519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status |= MCI_SDIOINTOPERMASK; 9529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 9539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status &= ~MCI_SDIOINTOPERMASK; 9549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->saved_irq0mask = status; 9558b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, status, MMCIMASK0); 9569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_unlock_irqrestore(&host->lock, flags); 9589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic const struct mmc_host_ops msmsdcc_ops = { 9619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .request = msmsdcc_request, 9629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .set_ios = msmsdcc_set_ios, 9639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .enable_sdio_irq = msmsdcc_enable_sdio_irq, 9649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}; 9659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 9679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_check_status(unsigned long data) 9689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = (struct msmsdcc_host *)data; 9709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned int status; 9719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->plat->status) { 9739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, 0); 9749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 9759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat status = host->plat->status(mmc_dev(host->mmc)); 9789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->eject = !status; 9799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status ^ host->oldstat) { 9800a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Slot status change detected (%d -> %d)\n", 9810a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(host->mmc), host->oldstat, status); 9829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (status) 9839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, (5 * HZ) / 2); 9849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else 9859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_detect_change(host->mmc, 0); 9869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 9879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->oldstat = status; 9899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatout: 9919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->timer.function) 9929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mod_timer(&host->timer, jiffies + HZ); 9939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 9949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 9959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic irqreturn_t 9969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_platform_status_irq(int irq, void *dev_id) 9979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 9989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 9999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_DEBUG "%s: %d\n", __func__, irq); 10019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_check_status((unsigned long) host); 10029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return IRQ_HANDLED; 10039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 10069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_status_notify_cb(int card_present, void *dev_id) 10079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = dev_id; 10099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), 10119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat card_present); 10129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_check_status((unsigned long) host); 10139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1015865c8064a2fb07100525097983966b8e789bde1aSan Mehatstatic void 1016865c8064a2fb07100525097983966b8e789bde1aSan Mehatmsmsdcc_busclk_expired(unsigned long _data) 1017865c8064a2fb07100525097983966b8e789bde1aSan Mehat{ 1018865c8064a2fb07100525097983966b8e789bde1aSan Mehat struct msmsdcc_host *host = (struct msmsdcc_host *) _data; 1019865c8064a2fb07100525097983966b8e789bde1aSan Mehat unsigned long flags; 1020865c8064a2fb07100525097983966b8e789bde1aSan Mehat 1021865c8064a2fb07100525097983966b8e789bde1aSan Mehat spin_lock_irqsave(&host->lock, flags); 1022c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat dev_info(mmc_dev(host->mmc), "Bus clock timer expired\n"); 1023865c8064a2fb07100525097983966b8e789bde1aSan Mehat if (host->clks_on) 1024c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 0); 1025865c8064a2fb07100525097983966b8e789bde1aSan Mehat spin_unlock_irqrestore(&host->lock, flags); 1026865c8064a2fb07100525097983966b8e789bde1aSan Mehat} 1027865c8064a2fb07100525097983966b8e789bde1aSan Mehat 10289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 10299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_init_dma(struct msmsdcc_host *host) 10309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data)); 10329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.host = host; 10339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.channel = -1; 10349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->dmares) 10369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENODEV; 10379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.nc = dma_alloc_coherent(NULL, 10399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat sizeof(struct msmsdcc_nc_dmadata), 10409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat &host->dma.nc_busaddr, 10419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat GFP_KERNEL); 10429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.nc == NULL) { 10430a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("Unable to allocate DMA buffer\n"); 10449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENOMEM; 10459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata)); 10479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.cmd_busaddr = host->dma.nc_busaddr; 10489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.cmdptr_busaddr = host->dma.nc_busaddr + 10499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat offsetof(struct msmsdcc_nc_dmadata, cmdptr); 10509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dma.channel = host->dmares->start; 10519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 10539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ 10569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void 10579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatdo_resume_work(struct work_struct *work) 10589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = 10609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat container_of(work, struct msmsdcc_host, resume_task); 10619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = host->mmc; 10629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 10649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_resume_host(mmc); 10659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 10669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat enable_irq(host->stat_irq); 10679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 10699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat#endif 10709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 10729d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_probe(struct platform_device *pdev) 10739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 10749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_platform_data *plat = pdev->dev.platform_data; 10759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host; 10769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc; 10779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *cmd_irqres = NULL; 10789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *pio_irqres = NULL; 10799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *stat_irqres = NULL; 10809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *memres = NULL; 10819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct resource *dmares = NULL; 10829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int ret; 10839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* must have platform data */ 10859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!plat) { 10860a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Platform data not available\n", __func__); 10879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -EINVAL; 10889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 10899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (pdev->id < 1 || pdev->id > 4) 10929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -EINVAL; 10939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (pdev->resource == NULL || pdev->num_resources < 2) { 10950a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Invalid resource\n", __func__); 10969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENXIO; 10979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 10989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 10999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); 11009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); 11019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 11029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "cmd_irq"); 11039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 11049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "pio_irq"); 11059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 11069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat "status_irq"); 11079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!cmd_irqres || !pio_irqres || !memres) { 11090a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Invalid resource\n", __func__); 11109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return -ENXIO; 11119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup our host structure 11159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); 11189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!mmc) { 11199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -ENOMEM; 11209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 11219d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host = mmc_priv(mmc); 11249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pdev_id = pdev->id; 11259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->plat = plat; 11269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->mmc = mmc; 112756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat host->curr.cmd = NULL; 11289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->cmdpoll = 1; 11309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->base = ioremap(memres->start, PAGE_SIZE); 11329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!host->base) { 11339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = -ENOMEM; 11349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto out; 11359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->cmd_irqres = cmd_irqres; 11389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pio_irqres = pio_irqres; 11399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->memres = memres; 11409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->dmares = dmares; 11419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat spin_lock_init(&host->lock); 11429d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11449d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup DMA 11459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_init_dma(host); 11479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11484adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat /* Get our clocks */ 11499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->pclk = clk_get(&pdev->dev, "sdc_pclk"); 11509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (IS_ERR(host->pclk)) { 11519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = PTR_ERR(host->pclk); 11529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto host_free; 11539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk = clk_get(&pdev->dev, "sdc_clk"); 11569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (IS_ERR(host->clk)) { 11579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = PTR_ERR(host->clk); 11584adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat goto pclk_put; 11599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11614adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat /* Enable clocks */ 1162c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat ret = msmsdcc_enable_clocks(host); 11639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 11649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_put; 11659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = clk_set_rate(host->clk, msmsdcc_fmin); 11679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) { 11680a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); 11699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_disable; 11709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 11719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11724adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80San Mehat host->pclk_rate = clk_get_rate(host->pclk); 11739d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->clk_rate = clk_get_rate(host->clk); 11749d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11759d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 11769d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup MMC host structure 11779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 11789d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->ops = &msmsdcc_ops; 11799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->f_min = msmsdcc_fmin; 11809d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->f_max = msmsdcc_fmax; 11819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->ocr_avail = plat->ocr_mask; 11829d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_4bit) 11849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_4_BIT_DATA; 11859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (msmsdcc_sdioirq) 11869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_SDIO_IRQ; 11879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; 11889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_phys_segs = NR_SG; 11909d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_hw_segs = NR_SG; 11919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */ 11929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_blk_count = 65536; 11939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ 11959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc->max_seg_size = mmc->max_req_size; 11969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 11978b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCIMASK0); 11988b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); 11999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12008b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); 12019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->saved_irq0mask = MCI_IRQENABLE; 12029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat /* 12049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat * Setup card detect change 12059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat */ 12069d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat memset(&host->timer, 0, sizeof(host->timer)); 12089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) { 12109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat unsigned long irqflags = IRQF_SHARED | 12119d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat (stat_irqres->flags & IRQF_TRIGGER_MASK); 12129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->stat_irq = stat_irqres->start; 12149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(host->stat_irq, 12159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat msmsdcc_platform_status_irq, 12169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat irqflags, 12179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (slot)", 12189d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host); 12199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) { 12200a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: Unable to get slot IRQ %d (%d)\n", 12210a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->stat_irq, ret); 12229d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto clk_disable; 12239d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 12249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (plat->register_status_notify) { 12259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat plat->register_status_notify(msmsdcc_status_notify_cb, host); 12269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else if (!plat->status) 12270a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_err("%s: No card detect facilities available\n", 12289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_hostname(mmc)); 12299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat else { 12309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat init_timer(&host->timer); 12319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.data = (unsigned long)host; 12329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.function = msmsdcc_check_status; 12339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->timer.expires = jiffies + HZ; 12349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat add_timer(&host->timer); 12359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 12369d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12379d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (plat->status) { 12389d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->oldstat = host->plat->status(mmc_dev(host->mmc)); 12399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host->eject = !host->oldstat; 12409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 12419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1242865c8064a2fb07100525097983966b8e789bde1aSan Mehat init_timer(&host->busclk_timer); 1243865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->busclk_timer.data = (unsigned long) host; 1244865c8064a2fb07100525097983966b8e789bde1aSan Mehat host->busclk_timer.function = msmsdcc_busclk_expired; 1245865c8064a2fb07100525097983966b8e789bde1aSan Mehat 12469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, 12479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (cmd)", host); 12489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 12499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto stat_irq_free; 12509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, 12529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat DRIVER_NAME " (pio)", host); 12539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (ret) 12549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat goto cmd_irq_free; 12559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_set_drvdata(pdev, mmc); 12579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_add_host(mmc); 12589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12590a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", 12600a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), (unsigned long long)memres->start, 12610a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (unsigned int) cmd_irqres->start, 12620a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (unsigned int) host->stat_irq, host->dma.channel); 12630a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc), 12640a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); 12650a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", 12660a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); 12670a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); 12680a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Power save feature enable = %d\n", 12690a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), msmsdcc_pwrsave); 12709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 12719d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->dma.channel != -1) { 12720a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", 12730a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); 12740a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", 12750a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches mmc_hostname(mmc), host->dma.cmd_busaddr, 12760a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches host->dma.cmdptr_busaddr); 12779d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } else 12780a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc)); 12799d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->timer.function) 12800a7ff7c7573011ec1f52052a8baeae68f4066ddeJoe Perches pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); 12819d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1282c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 1); 12839d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 12849d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat cmd_irq_free: 12859d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat free_irq(cmd_irqres->start, host); 12869d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat stat_irq_free: 12879d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 12889d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat free_irq(host->stat_irq, host); 12899d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_disable: 1290c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 0); 12919d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put: 12929d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put(host->clk); 12939d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat pclk_put: 12949d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat clk_put(host->pclk); 12959d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat host_free: 12969d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_free_host(mmc); 12979d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat out: 12989d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return ret; 12999d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13009d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13019d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 13029d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_suspend(struct platform_device *dev, pm_message_t state) 13039d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13049d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = mmc_get_drvdata(dev); 13059d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat int rc = 0; 130656a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat unsigned long flags; 13079d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13089d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 13099d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 13109d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 131156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat spin_lock_irqsave(&host->lock, flags); 13129d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (host->stat_irq) 13139d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat disable_irq(host->stat_irq); 13149d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13159d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) 13169d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat rc = mmc_suspend_host(mmc, state); 13179d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (!rc) { 13188b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, 0, MMCIMASK0); 13199d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13209d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 132156a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat spin_unlock_irqrestore(&host->lock, flags); 1322c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat if (host->clks_on) 1323c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 0); 13249d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 13259d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return rc; 13269d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13279d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13289d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int 13299d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmsmsdcc_resume(struct platform_device *dev) 13309d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13319d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct mmc_host *mmc = mmc_get_drvdata(dev); 13329d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13339d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc) { 13349d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat struct msmsdcc_host *host = mmc_priv(mmc); 13359d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 1336c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_enable_clocks(host); 133756a8b5b8ae81bd766e527a0e5274a087c3c1109dSan Mehat 13388b1c2ba274c8416afb7eab3bd788f98a917efe06San Mehat msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); 13399d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13409d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) 13419d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat mmc_resume_host(mmc); 13425b8a2fb34f5670b1f07483bfa40de9ce539dbdb2Roel Kluin if (host->stat_irq) 13439d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat enable_irq(host->stat_irq); 1344c7fc9370df1433486dfa9460a833fae664e8be6cSan Mehat msmsdcc_disable_clocks(host, 1); 13459d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat } 13469d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return 0; 13479d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13489d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13499d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic struct platform_driver msmsdcc_driver = { 13509d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .probe = msmsdcc_probe, 13519d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .suspend = msmsdcc_suspend, 13529d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .resume = msmsdcc_resume, 13539d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .driver = { 13549d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat .name = "msm_sdcc", 13559d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat }, 13569d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat}; 13579d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13589d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic int __init msmsdcc_init(void) 13599d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13609d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat return platform_driver_register(&msmsdcc_driver); 13619d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13629d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13639d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatstatic void __exit msmsdcc_exit(void) 13649d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat{ 13659d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat platform_driver_unregister(&msmsdcc_driver); 13669d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat} 13679d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13689d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_init(msmsdcc_init); 13699d2bd7383c71d38c60328a3dc8a946eda2013826San Mehatmodule_exit(msmsdcc_exit); 13709d2bd7383c71d38c60328a3dc8a946eda2013826San Mehat 13719d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); 13729d2bd7383c71d38c60328a3dc8a946eda2013826San MehatMODULE_LICENSE("GPL"); 1373