xref: /openbmc/linux/drivers/mmc/host/pxamci.c (revision d8cb70d1)
11c6a0718SPierre Ossman /*
270f10482SPierre Ossman  *  linux/drivers/mmc/host/pxa.c - PXA MMCI driver
31c6a0718SPierre Ossman  *
41c6a0718SPierre Ossman  *  Copyright (C) 2003 Russell King, All Rights Reserved.
51c6a0718SPierre Ossman  *
61c6a0718SPierre Ossman  * This program is free software; you can redistribute it and/or modify
71c6a0718SPierre Ossman  * it under the terms of the GNU General Public License version 2 as
81c6a0718SPierre Ossman  * published by the Free Software Foundation.
91c6a0718SPierre Ossman  *
101c6a0718SPierre Ossman  *  This hardware is really sick:
111c6a0718SPierre Ossman  *   - No way to clear interrupts.
121c6a0718SPierre Ossman  *   - Have to turn off the clock whenever we touch the device.
131c6a0718SPierre Ossman  *   - Doesn't tell you how many data blocks were transferred.
141c6a0718SPierre Ossman  *  Yuck!
151c6a0718SPierre Ossman  *
161c6a0718SPierre Ossman  *	1 and 3 byte data transfers not supported
171c6a0718SPierre Ossman  *	max block length up to 1023
181c6a0718SPierre Ossman  */
191c6a0718SPierre Ossman #include <linux/module.h>
201c6a0718SPierre Ossman #include <linux/init.h>
211c6a0718SPierre Ossman #include <linux/ioport.h>
221c6a0718SPierre Ossman #include <linux/platform_device.h>
231c6a0718SPierre Ossman #include <linux/delay.h>
241c6a0718SPierre Ossman #include <linux/interrupt.h>
251c6a0718SPierre Ossman #include <linux/dma-mapping.h>
26ebebd9b0SRussell King #include <linux/clk.h>
27ebebd9b0SRussell King #include <linux/err.h>
281c6a0718SPierre Ossman #include <linux/mmc/host.h>
291c6a0718SPierre Ossman 
301c6a0718SPierre Ossman #include <asm/dma.h>
311c6a0718SPierre Ossman #include <asm/io.h>
321c6a0718SPierre Ossman #include <asm/sizes.h>
331c6a0718SPierre Ossman 
341c6a0718SPierre Ossman #include <asm/arch/pxa-regs.h>
351c6a0718SPierre Ossman #include <asm/arch/mmc.h>
361c6a0718SPierre Ossman 
371c6a0718SPierre Ossman #include "pxamci.h"
381c6a0718SPierre Ossman 
391c6a0718SPierre Ossman #define DRIVER_NAME	"pxa2xx-mci"
401c6a0718SPierre Ossman 
411c6a0718SPierre Ossman #define NR_SG	1
42d8cb70d1SRussell King #define CLKRT_OFF	(~0)
431c6a0718SPierre Ossman 
441c6a0718SPierre Ossman struct pxamci_host {
451c6a0718SPierre Ossman 	struct mmc_host		*mmc;
461c6a0718SPierre Ossman 	spinlock_t		lock;
471c6a0718SPierre Ossman 	struct resource		*res;
481c6a0718SPierre Ossman 	void __iomem		*base;
49ebebd9b0SRussell King 	struct clk		*clk;
50ebebd9b0SRussell King 	unsigned long		clkrate;
511c6a0718SPierre Ossman 	int			irq;
521c6a0718SPierre Ossman 	int			dma;
531c6a0718SPierre Ossman 	unsigned int		clkrt;
541c6a0718SPierre Ossman 	unsigned int		cmdat;
551c6a0718SPierre Ossman 	unsigned int		imask;
561c6a0718SPierre Ossman 	unsigned int		power_mode;
571c6a0718SPierre Ossman 	struct pxamci_platform_data *pdata;
581c6a0718SPierre Ossman 
591c6a0718SPierre Ossman 	struct mmc_request	*mrq;
601c6a0718SPierre Ossman 	struct mmc_command	*cmd;
611c6a0718SPierre Ossman 	struct mmc_data		*data;
621c6a0718SPierre Ossman 
631c6a0718SPierre Ossman 	dma_addr_t		sg_dma;
641c6a0718SPierre Ossman 	struct pxa_dma_desc	*sg_cpu;
651c6a0718SPierre Ossman 	unsigned int		dma_len;
661c6a0718SPierre Ossman 
671c6a0718SPierre Ossman 	unsigned int		dma_dir;
681c6a0718SPierre Ossman };
691c6a0718SPierre Ossman 
701c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host)
711c6a0718SPierre Ossman {
721c6a0718SPierre Ossman 	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
731c6a0718SPierre Ossman 		unsigned long timeout = 10000;
741c6a0718SPierre Ossman 		unsigned int v;
751c6a0718SPierre Ossman 
761c6a0718SPierre Ossman 		writel(STOP_CLOCK, host->base + MMC_STRPCL);
771c6a0718SPierre Ossman 
781c6a0718SPierre Ossman 		do {
791c6a0718SPierre Ossman 			v = readl(host->base + MMC_STAT);
801c6a0718SPierre Ossman 			if (!(v & STAT_CLK_EN))
811c6a0718SPierre Ossman 				break;
821c6a0718SPierre Ossman 			udelay(1);
831c6a0718SPierre Ossman 		} while (timeout--);
841c6a0718SPierre Ossman 
851c6a0718SPierre Ossman 		if (v & STAT_CLK_EN)
861c6a0718SPierre Ossman 			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
871c6a0718SPierre Ossman 	}
881c6a0718SPierre Ossman }
891c6a0718SPierre Ossman 
901c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
911c6a0718SPierre Ossman {
921c6a0718SPierre Ossman 	unsigned long flags;
931c6a0718SPierre Ossman 
941c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
951c6a0718SPierre Ossman 	host->imask &= ~mask;
961c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
971c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
981c6a0718SPierre Ossman }
991c6a0718SPierre Ossman 
1001c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
1011c6a0718SPierre Ossman {
1021c6a0718SPierre Ossman 	unsigned long flags;
1031c6a0718SPierre Ossman 
1041c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
1051c6a0718SPierre Ossman 	host->imask |= mask;
1061c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1071c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1081c6a0718SPierre Ossman }
1091c6a0718SPierre Ossman 
1101c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
1111c6a0718SPierre Ossman {
1121c6a0718SPierre Ossman 	unsigned int nob = data->blocks;
1131c6a0718SPierre Ossman 	unsigned long long clks;
1141c6a0718SPierre Ossman 	unsigned int timeout;
1151c6a0718SPierre Ossman 	u32 dcmd;
1161c6a0718SPierre Ossman 	int i;
1171c6a0718SPierre Ossman 
1181c6a0718SPierre Ossman 	host->data = data;
1191c6a0718SPierre Ossman 
1201c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_STREAM)
1211c6a0718SPierre Ossman 		nob = 0xffff;
1221c6a0718SPierre Ossman 
1231c6a0718SPierre Ossman 	writel(nob, host->base + MMC_NOB);
1241c6a0718SPierre Ossman 	writel(data->blksz, host->base + MMC_BLKLEN);
1251c6a0718SPierre Ossman 
126ebebd9b0SRussell King 	clks = (unsigned long long)data->timeout_ns * host->clkrate;
1271c6a0718SPierre Ossman 	do_div(clks, 1000000000UL);
1281c6a0718SPierre Ossman 	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
1291c6a0718SPierre Ossman 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
1301c6a0718SPierre Ossman 
1311c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ) {
1321c6a0718SPierre Ossman 		host->dma_dir = DMA_FROM_DEVICE;
1331c6a0718SPierre Ossman 		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
1341c6a0718SPierre Ossman 		DRCMRTXMMC = 0;
1351c6a0718SPierre Ossman 		DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
1361c6a0718SPierre Ossman 	} else {
1371c6a0718SPierre Ossman 		host->dma_dir = DMA_TO_DEVICE;
1381c6a0718SPierre Ossman 		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
1391c6a0718SPierre Ossman 		DRCMRRXMMC = 0;
1401c6a0718SPierre Ossman 		DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
1411c6a0718SPierre Ossman 	}
1421c6a0718SPierre Ossman 
1431c6a0718SPierre Ossman 	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
1441c6a0718SPierre Ossman 
1451c6a0718SPierre Ossman 	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1461c6a0718SPierre Ossman 				   host->dma_dir);
1471c6a0718SPierre Ossman 
1481c6a0718SPierre Ossman 	for (i = 0; i < host->dma_len; i++) {
149c783837bSNicolas Pitre 		unsigned int length = sg_dma_len(&data->sg[i]);
150c783837bSNicolas Pitre 		host->sg_cpu[i].dcmd = dcmd | length;
151c783837bSNicolas Pitre 		if (length & 31 && !(data->flags & MMC_DATA_READ))
152c783837bSNicolas Pitre 			host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
1531c6a0718SPierre Ossman 		if (data->flags & MMC_DATA_READ) {
1541c6a0718SPierre Ossman 			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
1551c6a0718SPierre Ossman 			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
1561c6a0718SPierre Ossman 		} else {
1571c6a0718SPierre Ossman 			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
1581c6a0718SPierre Ossman 			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
1591c6a0718SPierre Ossman 		}
1601c6a0718SPierre Ossman 		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
1611c6a0718SPierre Ossman 					sizeof(struct pxa_dma_desc);
1621c6a0718SPierre Ossman 	}
1631c6a0718SPierre Ossman 	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
1641c6a0718SPierre Ossman 	wmb();
1651c6a0718SPierre Ossman 
1661c6a0718SPierre Ossman 	DDADR(host->dma) = host->sg_dma;
1671c6a0718SPierre Ossman 	DCSR(host->dma) = DCSR_RUN;
1681c6a0718SPierre Ossman }
1691c6a0718SPierre Ossman 
1701c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
1711c6a0718SPierre Ossman {
1721c6a0718SPierre Ossman 	WARN_ON(host->cmd != NULL);
1731c6a0718SPierre Ossman 	host->cmd = cmd;
1741c6a0718SPierre Ossman 
1751c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_BUSY)
1761c6a0718SPierre Ossman 		cmdat |= CMDAT_BUSY;
1771c6a0718SPierre Ossman 
1781c6a0718SPierre Ossman #define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
1791c6a0718SPierre Ossman 	switch (RSP_TYPE(mmc_resp_type(cmd))) {
1801c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
1811c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_SHORT;
1821c6a0718SPierre Ossman 		break;
1831c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R3):
1841c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R3;
1851c6a0718SPierre Ossman 		break;
1861c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R2):
1871c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R2;
1881c6a0718SPierre Ossman 		break;
1891c6a0718SPierre Ossman 	default:
1901c6a0718SPierre Ossman 		break;
1911c6a0718SPierre Ossman 	}
1921c6a0718SPierre Ossman 
1931c6a0718SPierre Ossman 	writel(cmd->opcode, host->base + MMC_CMD);
1941c6a0718SPierre Ossman 	writel(cmd->arg >> 16, host->base + MMC_ARGH);
1951c6a0718SPierre Ossman 	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
1961c6a0718SPierre Ossman 	writel(cmdat, host->base + MMC_CMDAT);
1971c6a0718SPierre Ossman 	writel(host->clkrt, host->base + MMC_CLKRT);
1981c6a0718SPierre Ossman 
1991c6a0718SPierre Ossman 	writel(START_CLOCK, host->base + MMC_STRPCL);
2001c6a0718SPierre Ossman 
2011c6a0718SPierre Ossman 	pxamci_enable_irq(host, END_CMD_RES);
2021c6a0718SPierre Ossman }
2031c6a0718SPierre Ossman 
2041c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
2051c6a0718SPierre Ossman {
2061c6a0718SPierre Ossman 	host->mrq = NULL;
2071c6a0718SPierre Ossman 	host->cmd = NULL;
2081c6a0718SPierre Ossman 	host->data = NULL;
2091c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
2101c6a0718SPierre Ossman }
2111c6a0718SPierre Ossman 
2121c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
2131c6a0718SPierre Ossman {
2141c6a0718SPierre Ossman 	struct mmc_command *cmd = host->cmd;
2151c6a0718SPierre Ossman 	int i;
2161c6a0718SPierre Ossman 	u32 v;
2171c6a0718SPierre Ossman 
2181c6a0718SPierre Ossman 	if (!cmd)
2191c6a0718SPierre Ossman 		return 0;
2201c6a0718SPierre Ossman 
2211c6a0718SPierre Ossman 	host->cmd = NULL;
2221c6a0718SPierre Ossman 
2231c6a0718SPierre Ossman 	/*
2241c6a0718SPierre Ossman 	 * Did I mention this is Sick.  We always need to
2251c6a0718SPierre Ossman 	 * discard the upper 8 bits of the first 16-bit word.
2261c6a0718SPierre Ossman 	 */
2271c6a0718SPierre Ossman 	v = readl(host->base + MMC_RES) & 0xffff;
2281c6a0718SPierre Ossman 	for (i = 0; i < 4; i++) {
2291c6a0718SPierre Ossman 		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
2301c6a0718SPierre Ossman 		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
2311c6a0718SPierre Ossman 		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
2321c6a0718SPierre Ossman 		v = w2;
2331c6a0718SPierre Ossman 	}
2341c6a0718SPierre Ossman 
2351c6a0718SPierre Ossman 	if (stat & STAT_TIME_OUT_RESPONSE) {
23617b0429dSPierre Ossman 		cmd->error = -ETIMEDOUT;
2371c6a0718SPierre Ossman 	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
2381c6a0718SPierre Ossman #ifdef CONFIG_PXA27x
2391c6a0718SPierre Ossman 		/*
2401c6a0718SPierre Ossman 		 * workaround for erratum #42:
2411c6a0718SPierre Ossman 		 * Intel PXA27x Family Processor Specification Update Rev 001
24290e07d9fSNicolas Pitre 		 * A bogus CRC error can appear if the msb of a 136 bit
24390e07d9fSNicolas Pitre 		 * response is a one.
2441c6a0718SPierre Ossman 		 */
24590e07d9fSNicolas Pitre 		if (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000) {
2461c6a0718SPierre Ossman 			pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
24790e07d9fSNicolas Pitre 		} else
2481c6a0718SPierre Ossman #endif
24917b0429dSPierre Ossman 		cmd->error = -EILSEQ;
2501c6a0718SPierre Ossman 	}
2511c6a0718SPierre Ossman 
2521c6a0718SPierre Ossman 	pxamci_disable_irq(host, END_CMD_RES);
25317b0429dSPierre Ossman 	if (host->data && !cmd->error) {
2541c6a0718SPierre Ossman 		pxamci_enable_irq(host, DATA_TRAN_DONE);
2551c6a0718SPierre Ossman 	} else {
2561c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
2571c6a0718SPierre Ossman 	}
2581c6a0718SPierre Ossman 
2591c6a0718SPierre Ossman 	return 1;
2601c6a0718SPierre Ossman }
2611c6a0718SPierre Ossman 
2621c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
2631c6a0718SPierre Ossman {
2641c6a0718SPierre Ossman 	struct mmc_data *data = host->data;
2651c6a0718SPierre Ossman 
2661c6a0718SPierre Ossman 	if (!data)
2671c6a0718SPierre Ossman 		return 0;
2681c6a0718SPierre Ossman 
2691c6a0718SPierre Ossman 	DCSR(host->dma) = 0;
2701c6a0718SPierre Ossman 	dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
2711c6a0718SPierre Ossman 		     host->dma_dir);
2721c6a0718SPierre Ossman 
2731c6a0718SPierre Ossman 	if (stat & STAT_READ_TIME_OUT)
27417b0429dSPierre Ossman 		data->error = -ETIMEDOUT;
2751c6a0718SPierre Ossman 	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
27617b0429dSPierre Ossman 		data->error = -EILSEQ;
2771c6a0718SPierre Ossman 
2781c6a0718SPierre Ossman 	/*
2791c6a0718SPierre Ossman 	 * There appears to be a hardware design bug here.  There seems to
2801c6a0718SPierre Ossman 	 * be no way to find out how much data was transferred to the card.
2811c6a0718SPierre Ossman 	 * This means that if there was an error on any block, we mark all
2821c6a0718SPierre Ossman 	 * data blocks as being in error.
2831c6a0718SPierre Ossman 	 */
28417b0429dSPierre Ossman 	if (!data->error)
2851c6a0718SPierre Ossman 		data->bytes_xfered = data->blocks * data->blksz;
2861c6a0718SPierre Ossman 	else
2871c6a0718SPierre Ossman 		data->bytes_xfered = 0;
2881c6a0718SPierre Ossman 
2891c6a0718SPierre Ossman 	pxamci_disable_irq(host, DATA_TRAN_DONE);
2901c6a0718SPierre Ossman 
2911c6a0718SPierre Ossman 	host->data = NULL;
2921c6a0718SPierre Ossman 	if (host->mrq->stop) {
2931c6a0718SPierre Ossman 		pxamci_stop_clock(host);
294df456f47SBridge Wu 		pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
2951c6a0718SPierre Ossman 	} else {
2961c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
2971c6a0718SPierre Ossman 	}
2981c6a0718SPierre Ossman 
2991c6a0718SPierre Ossman 	return 1;
3001c6a0718SPierre Ossman }
3011c6a0718SPierre Ossman 
3021c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid)
3031c6a0718SPierre Ossman {
3041c6a0718SPierre Ossman 	struct pxamci_host *host = devid;
3051c6a0718SPierre Ossman 	unsigned int ireg;
3061c6a0718SPierre Ossman 	int handled = 0;
3071c6a0718SPierre Ossman 
30881ab570fSBridge Wu 	ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
3091c6a0718SPierre Ossman 
3101c6a0718SPierre Ossman 	if (ireg) {
3111c6a0718SPierre Ossman 		unsigned stat = readl(host->base + MMC_STAT);
3121c6a0718SPierre Ossman 
3131c6a0718SPierre Ossman 		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
3141c6a0718SPierre Ossman 
3151c6a0718SPierre Ossman 		if (ireg & END_CMD_RES)
3161c6a0718SPierre Ossman 			handled |= pxamci_cmd_done(host, stat);
3171c6a0718SPierre Ossman 		if (ireg & DATA_TRAN_DONE)
3181c6a0718SPierre Ossman 			handled |= pxamci_data_done(host, stat);
3195d3ad4e8SBridge Wu 		if (ireg & SDIO_INT) {
3205d3ad4e8SBridge Wu 			mmc_signal_sdio_irq(host->mmc);
3215d3ad4e8SBridge Wu 			handled = 1;
3225d3ad4e8SBridge Wu 		}
3231c6a0718SPierre Ossman 	}
3241c6a0718SPierre Ossman 
3251c6a0718SPierre Ossman 	return IRQ_RETVAL(handled);
3261c6a0718SPierre Ossman }
3271c6a0718SPierre Ossman 
3281c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
3291c6a0718SPierre Ossman {
3301c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3311c6a0718SPierre Ossman 	unsigned int cmdat;
3321c6a0718SPierre Ossman 
3331c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
3341c6a0718SPierre Ossman 
3351c6a0718SPierre Ossman 	host->mrq = mrq;
3361c6a0718SPierre Ossman 
3371c6a0718SPierre Ossman 	pxamci_stop_clock(host);
3381c6a0718SPierre Ossman 
3391c6a0718SPierre Ossman 	cmdat = host->cmdat;
3401c6a0718SPierre Ossman 	host->cmdat &= ~CMDAT_INIT;
3411c6a0718SPierre Ossman 
3421c6a0718SPierre Ossman 	if (mrq->data) {
3431c6a0718SPierre Ossman 		pxamci_setup_data(host, mrq->data);
3441c6a0718SPierre Ossman 
3451c6a0718SPierre Ossman 		cmdat &= ~CMDAT_BUSY;
3461c6a0718SPierre Ossman 		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
3471c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_WRITE)
3481c6a0718SPierre Ossman 			cmdat |= CMDAT_WRITE;
3491c6a0718SPierre Ossman 
3501c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_STREAM)
3511c6a0718SPierre Ossman 			cmdat |= CMDAT_STREAM;
3521c6a0718SPierre Ossman 	}
3531c6a0718SPierre Ossman 
3541c6a0718SPierre Ossman 	pxamci_start_cmd(host, mrq->cmd, cmdat);
3551c6a0718SPierre Ossman }
3561c6a0718SPierre Ossman 
3571c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc)
3581c6a0718SPierre Ossman {
3591c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3601c6a0718SPierre Ossman 
3611c6a0718SPierre Ossman 	if (host->pdata && host->pdata->get_ro)
3621c6a0718SPierre Ossman 		return host->pdata->get_ro(mmc_dev(mmc));
3631c6a0718SPierre Ossman 	/* Host doesn't support read only detection so assume writeable */
3641c6a0718SPierre Ossman 	return 0;
3651c6a0718SPierre Ossman }
3661c6a0718SPierre Ossman 
3671c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3681c6a0718SPierre Ossman {
3691c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3701c6a0718SPierre Ossman 
3711c6a0718SPierre Ossman 	if (ios->clock) {
372ebebd9b0SRussell King 		unsigned long rate = host->clkrate;
373ebebd9b0SRussell King 		unsigned int clk = rate / ios->clock;
374ebebd9b0SRussell King 
375d8cb70d1SRussell King 		if (host->clkrt == CLKRT_OFF)
376d8cb70d1SRussell King 			clk_enable(host->clk);
377d8cb70d1SRussell King 
378ebebd9b0SRussell King 		/*
379ebebd9b0SRussell King 		 * clk might result in a lower divisor than we
380ebebd9b0SRussell King 		 * desire.  check for that condition and adjust
381ebebd9b0SRussell King 		 * as appropriate.
382ebebd9b0SRussell King 		 */
383ebebd9b0SRussell King 		if (rate / clk > ios->clock)
3841c6a0718SPierre Ossman 			clk <<= 1;
3851c6a0718SPierre Ossman 		host->clkrt = fls(clk) - 1;
3861c6a0718SPierre Ossman 
3871c6a0718SPierre Ossman 		/*
3881c6a0718SPierre Ossman 		 * we write clkrt on the next command
3891c6a0718SPierre Ossman 		 */
3901c6a0718SPierre Ossman 	} else {
3911c6a0718SPierre Ossman 		pxamci_stop_clock(host);
392d8cb70d1SRussell King 		if (host->clkrt != CLKRT_OFF) {
393d8cb70d1SRussell King 			host->clkrt = CLKRT_OFF;
394ebebd9b0SRussell King 			clk_disable(host->clk);
3951c6a0718SPierre Ossman 		}
396d8cb70d1SRussell King 	}
3971c6a0718SPierre Ossman 
3981c6a0718SPierre Ossman 	if (host->power_mode != ios->power_mode) {
3991c6a0718SPierre Ossman 		host->power_mode = ios->power_mode;
4001c6a0718SPierre Ossman 
4011c6a0718SPierre Ossman 		if (host->pdata && host->pdata->setpower)
4021c6a0718SPierre Ossman 			host->pdata->setpower(mmc_dev(mmc), ios->vdd);
4031c6a0718SPierre Ossman 
4041c6a0718SPierre Ossman 		if (ios->power_mode == MMC_POWER_ON)
4051c6a0718SPierre Ossman 			host->cmdat |= CMDAT_INIT;
4061c6a0718SPierre Ossman 	}
4071c6a0718SPierre Ossman 
408df456f47SBridge Wu 	if (ios->bus_width == MMC_BUS_WIDTH_4)
409df456f47SBridge Wu 		host->cmdat |= CMDAT_SD_4DAT;
410df456f47SBridge Wu 	else
411df456f47SBridge Wu 		host->cmdat &= ~CMDAT_SD_4DAT;
412df456f47SBridge Wu 
4131c6a0718SPierre Ossman 	pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
4141c6a0718SPierre Ossman 		 host->clkrt, host->cmdat);
4151c6a0718SPierre Ossman }
4161c6a0718SPierre Ossman 
4175d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
4185d3ad4e8SBridge Wu {
4195d3ad4e8SBridge Wu 	struct pxamci_host *pxa_host = mmc_priv(host);
4205d3ad4e8SBridge Wu 
4215d3ad4e8SBridge Wu 	if (enable)
4225d3ad4e8SBridge Wu 		pxamci_enable_irq(pxa_host, SDIO_INT);
4235d3ad4e8SBridge Wu 	else
4245d3ad4e8SBridge Wu 		pxamci_disable_irq(pxa_host, SDIO_INT);
4255d3ad4e8SBridge Wu }
4265d3ad4e8SBridge Wu 
4271c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = {
4281c6a0718SPierre Ossman 	.request		= pxamci_request,
4291c6a0718SPierre Ossman 	.get_ro			= pxamci_get_ro,
4301c6a0718SPierre Ossman 	.set_ios		= pxamci_set_ios,
4315d3ad4e8SBridge Wu 	.enable_sdio_irq	= pxamci_enable_sdio_irq,
4321c6a0718SPierre Ossman };
4331c6a0718SPierre Ossman 
4341c6a0718SPierre Ossman static void pxamci_dma_irq(int dma, void *devid)
4351c6a0718SPierre Ossman {
436c783837bSNicolas Pitre 	struct pxamci_host *host = devid;
437c783837bSNicolas Pitre 	int dcsr = DCSR(dma);
438c783837bSNicolas Pitre 	DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
439c783837bSNicolas Pitre 
440c783837bSNicolas Pitre 	if (dcsr & DCSR_ENDINTR) {
441c783837bSNicolas Pitre 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
442c783837bSNicolas Pitre 	} else {
443c783837bSNicolas Pitre 		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
444c783837bSNicolas Pitre 		       mmc_hostname(host->mmc), dma, dcsr);
445c783837bSNicolas Pitre 		host->data->error = -EIO;
446c783837bSNicolas Pitre 		pxamci_data_done(host, 0);
447c783837bSNicolas Pitre 	}
4481c6a0718SPierre Ossman }
4491c6a0718SPierre Ossman 
4501c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid)
4511c6a0718SPierre Ossman {
4521c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(devid);
4531c6a0718SPierre Ossman 
4541c6a0718SPierre Ossman 	mmc_detect_change(devid, host->pdata->detect_delay);
4551c6a0718SPierre Ossman 	return IRQ_HANDLED;
4561c6a0718SPierre Ossman }
4571c6a0718SPierre Ossman 
4581c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev)
4591c6a0718SPierre Ossman {
4601c6a0718SPierre Ossman 	struct mmc_host *mmc;
4611c6a0718SPierre Ossman 	struct pxamci_host *host = NULL;
4621c6a0718SPierre Ossman 	struct resource *r;
4631c6a0718SPierre Ossman 	int ret, irq;
4641c6a0718SPierre Ossman 
4651c6a0718SPierre Ossman 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4661c6a0718SPierre Ossman 	irq = platform_get_irq(pdev, 0);
4671c6a0718SPierre Ossman 	if (!r || irq < 0)
4681c6a0718SPierre Ossman 		return -ENXIO;
4691c6a0718SPierre Ossman 
4701c6a0718SPierre Ossman 	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
4711c6a0718SPierre Ossman 	if (!r)
4721c6a0718SPierre Ossman 		return -EBUSY;
4731c6a0718SPierre Ossman 
4741c6a0718SPierre Ossman 	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
4751c6a0718SPierre Ossman 	if (!mmc) {
4761c6a0718SPierre Ossman 		ret = -ENOMEM;
4771c6a0718SPierre Ossman 		goto out;
4781c6a0718SPierre Ossman 	}
4791c6a0718SPierre Ossman 
4801c6a0718SPierre Ossman 	mmc->ops = &pxamci_ops;
4811c6a0718SPierre Ossman 
4821c6a0718SPierre Ossman 	/*
4831c6a0718SPierre Ossman 	 * We can do SG-DMA, but we don't because we never know how much
4841c6a0718SPierre Ossman 	 * data we successfully wrote to the card.
4851c6a0718SPierre Ossman 	 */
4861c6a0718SPierre Ossman 	mmc->max_phys_segs = NR_SG;
4871c6a0718SPierre Ossman 
4881c6a0718SPierre Ossman 	/*
4891c6a0718SPierre Ossman 	 * Our hardware DMA can handle a maximum of one page per SG entry.
4901c6a0718SPierre Ossman 	 */
4911c6a0718SPierre Ossman 	mmc->max_seg_size = PAGE_SIZE;
4921c6a0718SPierre Ossman 
4931c6a0718SPierre Ossman 	/*
494fe2dc44eSNicolas Pitre 	 * Block length register is only 10 bits before PXA27x.
4951c6a0718SPierre Ossman 	 */
496fe2dc44eSNicolas Pitre 	mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048;
4971c6a0718SPierre Ossman 
4981c6a0718SPierre Ossman 	/*
4991c6a0718SPierre Ossman 	 * Block count register is 16 bits.
5001c6a0718SPierre Ossman 	 */
5011c6a0718SPierre Ossman 	mmc->max_blk_count = 65535;
5021c6a0718SPierre Ossman 
5031c6a0718SPierre Ossman 	host = mmc_priv(mmc);
5041c6a0718SPierre Ossman 	host->mmc = mmc;
5051c6a0718SPierre Ossman 	host->dma = -1;
5061c6a0718SPierre Ossman 	host->pdata = pdev->dev.platform_data;
507d8cb70d1SRussell King 	host->clkrt = CLKRT_OFF;
508ebebd9b0SRussell King 
509ebebd9b0SRussell King 	host->clk = clk_get(&pdev->dev, "MMCCLK");
510ebebd9b0SRussell King 	if (IS_ERR(host->clk)) {
511ebebd9b0SRussell King 		ret = PTR_ERR(host->clk);
512ebebd9b0SRussell King 		host->clk = NULL;
513ebebd9b0SRussell King 		goto out;
514ebebd9b0SRussell King 	}
515ebebd9b0SRussell King 
516ebebd9b0SRussell King 	host->clkrate = clk_get_rate(host->clk);
517ebebd9b0SRussell King 
518ebebd9b0SRussell King 	/*
519ebebd9b0SRussell King 	 * Calculate minimum clock rate, rounding up.
520ebebd9b0SRussell King 	 */
521ebebd9b0SRussell King 	mmc->f_min = (host->clkrate + 63) / 64;
522ebebd9b0SRussell King 	mmc->f_max = host->clkrate;
523ebebd9b0SRussell King 
5241c6a0718SPierre Ossman 	mmc->ocr_avail = host->pdata ?
5251c6a0718SPierre Ossman 			 host->pdata->ocr_mask :
5261c6a0718SPierre Ossman 			 MMC_VDD_32_33|MMC_VDD_33_34;
527df456f47SBridge Wu 	mmc->caps = 0;
5285d3ad4e8SBridge Wu 	host->cmdat = 0;
5295d3ad4e8SBridge Wu 	if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) {
5305d3ad4e8SBridge Wu 		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
5315d3ad4e8SBridge Wu 		host->cmdat |= CMDAT_SDIO_INT_EN;
5325d3ad4e8SBridge Wu 	}
5331c6a0718SPierre Ossman 
5341c6a0718SPierre Ossman 	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
5351c6a0718SPierre Ossman 	if (!host->sg_cpu) {
5361c6a0718SPierre Ossman 		ret = -ENOMEM;
5371c6a0718SPierre Ossman 		goto out;
5381c6a0718SPierre Ossman 	}
5391c6a0718SPierre Ossman 
5401c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
5411c6a0718SPierre Ossman 	host->res = r;
5421c6a0718SPierre Ossman 	host->irq = irq;
5431c6a0718SPierre Ossman 	host->imask = MMC_I_MASK_ALL;
5441c6a0718SPierre Ossman 
5451c6a0718SPierre Ossman 	host->base = ioremap(r->start, SZ_4K);
5461c6a0718SPierre Ossman 	if (!host->base) {
5471c6a0718SPierre Ossman 		ret = -ENOMEM;
5481c6a0718SPierre Ossman 		goto out;
5491c6a0718SPierre Ossman 	}
5501c6a0718SPierre Ossman 
5511c6a0718SPierre Ossman 	/*
5521c6a0718SPierre Ossman 	 * Ensure that the host controller is shut down, and setup
5531c6a0718SPierre Ossman 	 * with our defaults.
5541c6a0718SPierre Ossman 	 */
5551c6a0718SPierre Ossman 	pxamci_stop_clock(host);
5561c6a0718SPierre Ossman 	writel(0, host->base + MMC_SPI);
5571c6a0718SPierre Ossman 	writel(64, host->base + MMC_RESTO);
5581c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
5591c6a0718SPierre Ossman 
5601c6a0718SPierre Ossman 	host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
5611c6a0718SPierre Ossman 				    pxamci_dma_irq, host);
5621c6a0718SPierre Ossman 	if (host->dma < 0) {
5631c6a0718SPierre Ossman 		ret = -EBUSY;
5641c6a0718SPierre Ossman 		goto out;
5651c6a0718SPierre Ossman 	}
5661c6a0718SPierre Ossman 
5671c6a0718SPierre Ossman 	ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
5681c6a0718SPierre Ossman 	if (ret)
5691c6a0718SPierre Ossman 		goto out;
5701c6a0718SPierre Ossman 
5711c6a0718SPierre Ossman 	platform_set_drvdata(pdev, mmc);
5721c6a0718SPierre Ossman 
5731c6a0718SPierre Ossman 	if (host->pdata && host->pdata->init)
5741c6a0718SPierre Ossman 		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
5751c6a0718SPierre Ossman 
5761c6a0718SPierre Ossman 	mmc_add_host(mmc);
5771c6a0718SPierre Ossman 
5781c6a0718SPierre Ossman 	return 0;
5791c6a0718SPierre Ossman 
5801c6a0718SPierre Ossman  out:
5811c6a0718SPierre Ossman 	if (host) {
5821c6a0718SPierre Ossman 		if (host->dma >= 0)
5831c6a0718SPierre Ossman 			pxa_free_dma(host->dma);
5841c6a0718SPierre Ossman 		if (host->base)
5851c6a0718SPierre Ossman 			iounmap(host->base);
5861c6a0718SPierre Ossman 		if (host->sg_cpu)
5871c6a0718SPierre Ossman 			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
588ebebd9b0SRussell King 		if (host->clk)
589ebebd9b0SRussell King 			clk_put(host->clk);
5901c6a0718SPierre Ossman 	}
5911c6a0718SPierre Ossman 	if (mmc)
5921c6a0718SPierre Ossman 		mmc_free_host(mmc);
5931c6a0718SPierre Ossman 	release_resource(r);
5941c6a0718SPierre Ossman 	return ret;
5951c6a0718SPierre Ossman }
5961c6a0718SPierre Ossman 
5971c6a0718SPierre Ossman static int pxamci_remove(struct platform_device *pdev)
5981c6a0718SPierre Ossman {
5991c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(pdev);
6001c6a0718SPierre Ossman 
6011c6a0718SPierre Ossman 	platform_set_drvdata(pdev, NULL);
6021c6a0718SPierre Ossman 
6031c6a0718SPierre Ossman 	if (mmc) {
6041c6a0718SPierre Ossman 		struct pxamci_host *host = mmc_priv(mmc);
6051c6a0718SPierre Ossman 
6061c6a0718SPierre Ossman 		if (host->pdata && host->pdata->exit)
6071c6a0718SPierre Ossman 			host->pdata->exit(&pdev->dev, mmc);
6081c6a0718SPierre Ossman 
6091c6a0718SPierre Ossman 		mmc_remove_host(mmc);
6101c6a0718SPierre Ossman 
6111c6a0718SPierre Ossman 		pxamci_stop_clock(host);
6121c6a0718SPierre Ossman 		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
6131c6a0718SPierre Ossman 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
6141c6a0718SPierre Ossman 		       host->base + MMC_I_MASK);
6151c6a0718SPierre Ossman 
6161c6a0718SPierre Ossman 		DRCMRRXMMC = 0;
6171c6a0718SPierre Ossman 		DRCMRTXMMC = 0;
6181c6a0718SPierre Ossman 
6191c6a0718SPierre Ossman 		free_irq(host->irq, host);
6201c6a0718SPierre Ossman 		pxa_free_dma(host->dma);
6211c6a0718SPierre Ossman 		iounmap(host->base);
6221c6a0718SPierre Ossman 		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
6231c6a0718SPierre Ossman 
624ebebd9b0SRussell King 		clk_put(host->clk);
625ebebd9b0SRussell King 
6261c6a0718SPierre Ossman 		release_resource(host->res);
6271c6a0718SPierre Ossman 
6281c6a0718SPierre Ossman 		mmc_free_host(mmc);
6291c6a0718SPierre Ossman 	}
6301c6a0718SPierre Ossman 	return 0;
6311c6a0718SPierre Ossman }
6321c6a0718SPierre Ossman 
6331c6a0718SPierre Ossman #ifdef CONFIG_PM
6341c6a0718SPierre Ossman static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
6351c6a0718SPierre Ossman {
6361c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(dev);
6371c6a0718SPierre Ossman 	int ret = 0;
6381c6a0718SPierre Ossman 
6391c6a0718SPierre Ossman 	if (mmc)
6401c6a0718SPierre Ossman 		ret = mmc_suspend_host(mmc, state);
6411c6a0718SPierre Ossman 
6421c6a0718SPierre Ossman 	return ret;
6431c6a0718SPierre Ossman }
6441c6a0718SPierre Ossman 
6451c6a0718SPierre Ossman static int pxamci_resume(struct platform_device *dev)
6461c6a0718SPierre Ossman {
6471c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(dev);
6481c6a0718SPierre Ossman 	int ret = 0;
6491c6a0718SPierre Ossman 
6501c6a0718SPierre Ossman 	if (mmc)
6511c6a0718SPierre Ossman 		ret = mmc_resume_host(mmc);
6521c6a0718SPierre Ossman 
6531c6a0718SPierre Ossman 	return ret;
6541c6a0718SPierre Ossman }
6551c6a0718SPierre Ossman #else
6561c6a0718SPierre Ossman #define pxamci_suspend	NULL
6571c6a0718SPierre Ossman #define pxamci_resume	NULL
6581c6a0718SPierre Ossman #endif
6591c6a0718SPierre Ossman 
6601c6a0718SPierre Ossman static struct platform_driver pxamci_driver = {
6611c6a0718SPierre Ossman 	.probe		= pxamci_probe,
6621c6a0718SPierre Ossman 	.remove		= pxamci_remove,
6631c6a0718SPierre Ossman 	.suspend	= pxamci_suspend,
6641c6a0718SPierre Ossman 	.resume		= pxamci_resume,
6651c6a0718SPierre Ossman 	.driver		= {
6661c6a0718SPierre Ossman 		.name	= DRIVER_NAME,
6671c6a0718SPierre Ossman 	},
6681c6a0718SPierre Ossman };
6691c6a0718SPierre Ossman 
6701c6a0718SPierre Ossman static int __init pxamci_init(void)
6711c6a0718SPierre Ossman {
6721c6a0718SPierre Ossman 	return platform_driver_register(&pxamci_driver);
6731c6a0718SPierre Ossman }
6741c6a0718SPierre Ossman 
6751c6a0718SPierre Ossman static void __exit pxamci_exit(void)
6761c6a0718SPierre Ossman {
6771c6a0718SPierre Ossman 	platform_driver_unregister(&pxamci_driver);
6781c6a0718SPierre Ossman }
6791c6a0718SPierre Ossman 
6801c6a0718SPierre Ossman module_init(pxamci_init);
6811c6a0718SPierre Ossman module_exit(pxamci_exit);
6821c6a0718SPierre Ossman 
6831c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
6841c6a0718SPierre Ossman MODULE_LICENSE("GPL");
685