xref: /openbmc/linux/drivers/mmc/host/pxamci.c (revision b6018958)
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>
2905678a96SRussell King #include <linux/io.h>
301c6a0718SPierre Ossman 
311c6a0718SPierre Ossman #include <asm/sizes.h>
321c6a0718SPierre Ossman 
33dcea83adSRussell King #include <mach/dma.h>
3405678a96SRussell King #include <mach/hardware.h>
35a09e64fbSRussell King #include <mach/pxa-regs.h>
36a09e64fbSRussell King #include <mach/mmc.h>
371c6a0718SPierre Ossman 
381c6a0718SPierre Ossman #include "pxamci.h"
391c6a0718SPierre Ossman 
401c6a0718SPierre Ossman #define DRIVER_NAME	"pxa2xx-mci"
411c6a0718SPierre Ossman 
421c6a0718SPierre Ossman #define NR_SG	1
43d8cb70d1SRussell King #define CLKRT_OFF	(~0)
441c6a0718SPierre Ossman 
451c6a0718SPierre Ossman struct pxamci_host {
461c6a0718SPierre Ossman 	struct mmc_host		*mmc;
471c6a0718SPierre Ossman 	spinlock_t		lock;
481c6a0718SPierre Ossman 	struct resource		*res;
491c6a0718SPierre Ossman 	void __iomem		*base;
50ebebd9b0SRussell King 	struct clk		*clk;
51ebebd9b0SRussell King 	unsigned long		clkrate;
521c6a0718SPierre Ossman 	int			irq;
531c6a0718SPierre Ossman 	int			dma;
541c6a0718SPierre Ossman 	unsigned int		clkrt;
551c6a0718SPierre Ossman 	unsigned int		cmdat;
561c6a0718SPierre Ossman 	unsigned int		imask;
571c6a0718SPierre Ossman 	unsigned int		power_mode;
581c6a0718SPierre Ossman 	struct pxamci_platform_data *pdata;
591c6a0718SPierre Ossman 
601c6a0718SPierre Ossman 	struct mmc_request	*mrq;
611c6a0718SPierre Ossman 	struct mmc_command	*cmd;
621c6a0718SPierre Ossman 	struct mmc_data		*data;
631c6a0718SPierre Ossman 
641c6a0718SPierre Ossman 	dma_addr_t		sg_dma;
651c6a0718SPierre Ossman 	struct pxa_dma_desc	*sg_cpu;
661c6a0718SPierre Ossman 	unsigned int		dma_len;
671c6a0718SPierre Ossman 
681c6a0718SPierre Ossman 	unsigned int		dma_dir;
699a788c6bSBridge Wu 	unsigned int		dma_drcmrrx;
709a788c6bSBridge Wu 	unsigned int		dma_drcmrtx;
711c6a0718SPierre Ossman };
721c6a0718SPierre Ossman 
731c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host)
741c6a0718SPierre Ossman {
751c6a0718SPierre Ossman 	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
761c6a0718SPierre Ossman 		unsigned long timeout = 10000;
771c6a0718SPierre Ossman 		unsigned int v;
781c6a0718SPierre Ossman 
791c6a0718SPierre Ossman 		writel(STOP_CLOCK, host->base + MMC_STRPCL);
801c6a0718SPierre Ossman 
811c6a0718SPierre Ossman 		do {
821c6a0718SPierre Ossman 			v = readl(host->base + MMC_STAT);
831c6a0718SPierre Ossman 			if (!(v & STAT_CLK_EN))
841c6a0718SPierre Ossman 				break;
851c6a0718SPierre Ossman 			udelay(1);
861c6a0718SPierre Ossman 		} while (timeout--);
871c6a0718SPierre Ossman 
881c6a0718SPierre Ossman 		if (v & STAT_CLK_EN)
891c6a0718SPierre Ossman 			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
901c6a0718SPierre Ossman 	}
911c6a0718SPierre Ossman }
921c6a0718SPierre Ossman 
931c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
941c6a0718SPierre Ossman {
951c6a0718SPierre Ossman 	unsigned long flags;
961c6a0718SPierre Ossman 
971c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
981c6a0718SPierre Ossman 	host->imask &= ~mask;
991c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1001c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1011c6a0718SPierre Ossman }
1021c6a0718SPierre Ossman 
1031c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
1041c6a0718SPierre Ossman {
1051c6a0718SPierre Ossman 	unsigned long flags;
1061c6a0718SPierre Ossman 
1071c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
1081c6a0718SPierre Ossman 	host->imask |= mask;
1091c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1101c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1111c6a0718SPierre Ossman }
1121c6a0718SPierre Ossman 
1131c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
1141c6a0718SPierre Ossman {
1151c6a0718SPierre Ossman 	unsigned int nob = data->blocks;
1161c6a0718SPierre Ossman 	unsigned long long clks;
1171c6a0718SPierre Ossman 	unsigned int timeout;
11897f8571eSPhilipp Zabel 	bool dalgn = 0;
1191c6a0718SPierre Ossman 	u32 dcmd;
1201c6a0718SPierre Ossman 	int i;
1211c6a0718SPierre Ossman 
1221c6a0718SPierre Ossman 	host->data = data;
1231c6a0718SPierre Ossman 
1241c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_STREAM)
1251c6a0718SPierre Ossman 		nob = 0xffff;
1261c6a0718SPierre Ossman 
1271c6a0718SPierre Ossman 	writel(nob, host->base + MMC_NOB);
1281c6a0718SPierre Ossman 	writel(data->blksz, host->base + MMC_BLKLEN);
1291c6a0718SPierre Ossman 
130ebebd9b0SRussell King 	clks = (unsigned long long)data->timeout_ns * host->clkrate;
1311c6a0718SPierre Ossman 	do_div(clks, 1000000000UL);
1321c6a0718SPierre Ossman 	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
1331c6a0718SPierre Ossman 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
1341c6a0718SPierre Ossman 
1351c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ) {
1361c6a0718SPierre Ossman 		host->dma_dir = DMA_FROM_DEVICE;
1371c6a0718SPierre Ossman 		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
1389a788c6bSBridge Wu 		DRCMR(host->dma_drcmrtx) = 0;
1399a788c6bSBridge Wu 		DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
1401c6a0718SPierre Ossman 	} else {
1411c6a0718SPierre Ossman 		host->dma_dir = DMA_TO_DEVICE;
1421c6a0718SPierre Ossman 		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
1439a788c6bSBridge Wu 		DRCMR(host->dma_drcmrrx) = 0;
1449a788c6bSBridge Wu 		DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
1451c6a0718SPierre Ossman 	}
1461c6a0718SPierre Ossman 
1471c6a0718SPierre Ossman 	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
1481c6a0718SPierre Ossman 
1491c6a0718SPierre Ossman 	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1501c6a0718SPierre Ossman 				   host->dma_dir);
1511c6a0718SPierre Ossman 
1521c6a0718SPierre Ossman 	for (i = 0; i < host->dma_len; i++) {
153c783837bSNicolas Pitre 		unsigned int length = sg_dma_len(&data->sg[i]);
154c783837bSNicolas Pitre 		host->sg_cpu[i].dcmd = dcmd | length;
155c783837bSNicolas Pitre 		if (length & 31 && !(data->flags & MMC_DATA_READ))
156c783837bSNicolas Pitre 			host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
15797f8571eSPhilipp Zabel 		/* Not aligned to 8-byte boundary? */
15897f8571eSPhilipp Zabel 		if (sg_dma_address(&data->sg[i]) & 0x7)
15997f8571eSPhilipp Zabel 			dalgn = 1;
1601c6a0718SPierre Ossman 		if (data->flags & MMC_DATA_READ) {
1611c6a0718SPierre Ossman 			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
1621c6a0718SPierre Ossman 			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
1631c6a0718SPierre Ossman 		} else {
1641c6a0718SPierre Ossman 			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
1651c6a0718SPierre Ossman 			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
1661c6a0718SPierre Ossman 		}
1671c6a0718SPierre Ossman 		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
1681c6a0718SPierre Ossman 					sizeof(struct pxa_dma_desc);
1691c6a0718SPierre Ossman 	}
1701c6a0718SPierre Ossman 	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
1711c6a0718SPierre Ossman 	wmb();
1721c6a0718SPierre Ossman 
17397f8571eSPhilipp Zabel 	/*
17497f8571eSPhilipp Zabel 	 * The PXA27x DMA controller encounters overhead when working with
17597f8571eSPhilipp Zabel 	 * unaligned (to 8-byte boundaries) data, so switch on byte alignment
17697f8571eSPhilipp Zabel 	 * mode only if we have unaligned data.
17797f8571eSPhilipp Zabel 	 */
17897f8571eSPhilipp Zabel 	if (dalgn)
17997f8571eSPhilipp Zabel 		DALGN |= (1 << host->dma);
18097f8571eSPhilipp Zabel 	else
1814fe16897SKarl Beldan 		DALGN &= ~(1 << host->dma);
1821c6a0718SPierre Ossman 	DDADR(host->dma) = host->sg_dma;
183b6018958SCliff Brake 
184b6018958SCliff Brake 	/*
185b6018958SCliff Brake 	 * workaround for erratum #91:
186b6018958SCliff Brake 	 * only start DMA now if we are doing a read,
187b6018958SCliff Brake 	 * otherwise we wait until CMD/RESP has finished
188b6018958SCliff Brake 	 * before starting DMA.
189b6018958SCliff Brake 	 */
190b6018958SCliff Brake 	if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
1911c6a0718SPierre Ossman 		DCSR(host->dma) = DCSR_RUN;
1921c6a0718SPierre Ossman }
1931c6a0718SPierre Ossman 
1941c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
1951c6a0718SPierre Ossman {
1961c6a0718SPierre Ossman 	WARN_ON(host->cmd != NULL);
1971c6a0718SPierre Ossman 	host->cmd = cmd;
1981c6a0718SPierre Ossman 
1991c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_BUSY)
2001c6a0718SPierre Ossman 		cmdat |= CMDAT_BUSY;
2011c6a0718SPierre Ossman 
2021c6a0718SPierre Ossman #define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
2031c6a0718SPierre Ossman 	switch (RSP_TYPE(mmc_resp_type(cmd))) {
2041c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
2051c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_SHORT;
2061c6a0718SPierre Ossman 		break;
2071c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R3):
2081c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R3;
2091c6a0718SPierre Ossman 		break;
2101c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R2):
2111c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R2;
2121c6a0718SPierre Ossman 		break;
2131c6a0718SPierre Ossman 	default:
2141c6a0718SPierre Ossman 		break;
2151c6a0718SPierre Ossman 	}
2161c6a0718SPierre Ossman 
2171c6a0718SPierre Ossman 	writel(cmd->opcode, host->base + MMC_CMD);
2181c6a0718SPierre Ossman 	writel(cmd->arg >> 16, host->base + MMC_ARGH);
2191c6a0718SPierre Ossman 	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
2201c6a0718SPierre Ossman 	writel(cmdat, host->base + MMC_CMDAT);
2211c6a0718SPierre Ossman 	writel(host->clkrt, host->base + MMC_CLKRT);
2221c6a0718SPierre Ossman 
2231c6a0718SPierre Ossman 	writel(START_CLOCK, host->base + MMC_STRPCL);
2241c6a0718SPierre Ossman 
2251c6a0718SPierre Ossman 	pxamci_enable_irq(host, END_CMD_RES);
2261c6a0718SPierre Ossman }
2271c6a0718SPierre Ossman 
2281c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
2291c6a0718SPierre Ossman {
2301c6a0718SPierre Ossman 	host->mrq = NULL;
2311c6a0718SPierre Ossman 	host->cmd = NULL;
2321c6a0718SPierre Ossman 	host->data = NULL;
2331c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
2341c6a0718SPierre Ossman }
2351c6a0718SPierre Ossman 
2361c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
2371c6a0718SPierre Ossman {
2381c6a0718SPierre Ossman 	struct mmc_command *cmd = host->cmd;
2391c6a0718SPierre Ossman 	int i;
2401c6a0718SPierre Ossman 	u32 v;
2411c6a0718SPierre Ossman 
2421c6a0718SPierre Ossman 	if (!cmd)
2431c6a0718SPierre Ossman 		return 0;
2441c6a0718SPierre Ossman 
2451c6a0718SPierre Ossman 	host->cmd = NULL;
2461c6a0718SPierre Ossman 
2471c6a0718SPierre Ossman 	/*
2481c6a0718SPierre Ossman 	 * Did I mention this is Sick.  We always need to
2491c6a0718SPierre Ossman 	 * discard the upper 8 bits of the first 16-bit word.
2501c6a0718SPierre Ossman 	 */
2511c6a0718SPierre Ossman 	v = readl(host->base + MMC_RES) & 0xffff;
2521c6a0718SPierre Ossman 	for (i = 0; i < 4; i++) {
2531c6a0718SPierre Ossman 		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
2541c6a0718SPierre Ossman 		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
2551c6a0718SPierre Ossman 		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
2561c6a0718SPierre Ossman 		v = w2;
2571c6a0718SPierre Ossman 	}
2581c6a0718SPierre Ossman 
2591c6a0718SPierre Ossman 	if (stat & STAT_TIME_OUT_RESPONSE) {
26017b0429dSPierre Ossman 		cmd->error = -ETIMEDOUT;
2611c6a0718SPierre Ossman 	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
2621c6a0718SPierre Ossman 		/*
2631c6a0718SPierre Ossman 		 * workaround for erratum #42:
2641c6a0718SPierre Ossman 		 * Intel PXA27x Family Processor Specification Update Rev 001
26590e07d9fSNicolas Pitre 		 * A bogus CRC error can appear if the msb of a 136 bit
26690e07d9fSNicolas Pitre 		 * response is a one.
2671c6a0718SPierre Ossman 		 */
268e10a854cSCliff Brake 		if (cpu_is_pxa27x() &&
269e10a854cSCliff Brake 		    (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000))
2701c6a0718SPierre Ossman 			pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
271e10a854cSCliff Brake 		else
27217b0429dSPierre Ossman 			cmd->error = -EILSEQ;
2731c6a0718SPierre Ossman 	}
2741c6a0718SPierre Ossman 
2751c6a0718SPierre Ossman 	pxamci_disable_irq(host, END_CMD_RES);
27617b0429dSPierre Ossman 	if (host->data && !cmd->error) {
2771c6a0718SPierre Ossman 		pxamci_enable_irq(host, DATA_TRAN_DONE);
278b6018958SCliff Brake 		/*
279b6018958SCliff Brake 		 * workaround for erratum #91, if doing write
280b6018958SCliff Brake 		 * enable DMA late
281b6018958SCliff Brake 		 */
282b6018958SCliff Brake 		if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
283b6018958SCliff Brake 			DCSR(host->dma) = DCSR_RUN;
2841c6a0718SPierre Ossman 	} else {
2851c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
2861c6a0718SPierre Ossman 	}
2871c6a0718SPierre Ossman 
2881c6a0718SPierre Ossman 	return 1;
2891c6a0718SPierre Ossman }
2901c6a0718SPierre Ossman 
2911c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
2921c6a0718SPierre Ossman {
2931c6a0718SPierre Ossman 	struct mmc_data *data = host->data;
2941c6a0718SPierre Ossman 
2951c6a0718SPierre Ossman 	if (!data)
2961c6a0718SPierre Ossman 		return 0;
2971c6a0718SPierre Ossman 
2981c6a0718SPierre Ossman 	DCSR(host->dma) = 0;
299c00a46abSVernon Sauder 	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
3001c6a0718SPierre Ossman 		     host->dma_dir);
3011c6a0718SPierre Ossman 
3021c6a0718SPierre Ossman 	if (stat & STAT_READ_TIME_OUT)
30317b0429dSPierre Ossman 		data->error = -ETIMEDOUT;
3041c6a0718SPierre Ossman 	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
30517b0429dSPierre Ossman 		data->error = -EILSEQ;
3061c6a0718SPierre Ossman 
3071c6a0718SPierre Ossman 	/*
3081c6a0718SPierre Ossman 	 * There appears to be a hardware design bug here.  There seems to
3091c6a0718SPierre Ossman 	 * be no way to find out how much data was transferred to the card.
3101c6a0718SPierre Ossman 	 * This means that if there was an error on any block, we mark all
3111c6a0718SPierre Ossman 	 * data blocks as being in error.
3121c6a0718SPierre Ossman 	 */
31317b0429dSPierre Ossman 	if (!data->error)
3141c6a0718SPierre Ossman 		data->bytes_xfered = data->blocks * data->blksz;
3151c6a0718SPierre Ossman 	else
3161c6a0718SPierre Ossman 		data->bytes_xfered = 0;
3171c6a0718SPierre Ossman 
3181c6a0718SPierre Ossman 	pxamci_disable_irq(host, DATA_TRAN_DONE);
3191c6a0718SPierre Ossman 
3201c6a0718SPierre Ossman 	host->data = NULL;
3211c6a0718SPierre Ossman 	if (host->mrq->stop) {
3221c6a0718SPierre Ossman 		pxamci_stop_clock(host);
323df456f47SBridge Wu 		pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
3241c6a0718SPierre Ossman 	} else {
3251c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
3261c6a0718SPierre Ossman 	}
3271c6a0718SPierre Ossman 
3281c6a0718SPierre Ossman 	return 1;
3291c6a0718SPierre Ossman }
3301c6a0718SPierre Ossman 
3311c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid)
3321c6a0718SPierre Ossman {
3331c6a0718SPierre Ossman 	struct pxamci_host *host = devid;
3341c6a0718SPierre Ossman 	unsigned int ireg;
3351c6a0718SPierre Ossman 	int handled = 0;
3361c6a0718SPierre Ossman 
33781ab570fSBridge Wu 	ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
3381c6a0718SPierre Ossman 
3391c6a0718SPierre Ossman 	if (ireg) {
3401c6a0718SPierre Ossman 		unsigned stat = readl(host->base + MMC_STAT);
3411c6a0718SPierre Ossman 
3421c6a0718SPierre Ossman 		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
3431c6a0718SPierre Ossman 
3441c6a0718SPierre Ossman 		if (ireg & END_CMD_RES)
3451c6a0718SPierre Ossman 			handled |= pxamci_cmd_done(host, stat);
3461c6a0718SPierre Ossman 		if (ireg & DATA_TRAN_DONE)
3471c6a0718SPierre Ossman 			handled |= pxamci_data_done(host, stat);
3485d3ad4e8SBridge Wu 		if (ireg & SDIO_INT) {
3495d3ad4e8SBridge Wu 			mmc_signal_sdio_irq(host->mmc);
3505d3ad4e8SBridge Wu 			handled = 1;
3515d3ad4e8SBridge Wu 		}
3521c6a0718SPierre Ossman 	}
3531c6a0718SPierre Ossman 
3541c6a0718SPierre Ossman 	return IRQ_RETVAL(handled);
3551c6a0718SPierre Ossman }
3561c6a0718SPierre Ossman 
3571c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
3581c6a0718SPierre Ossman {
3591c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3601c6a0718SPierre Ossman 	unsigned int cmdat;
3611c6a0718SPierre Ossman 
3621c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
3631c6a0718SPierre Ossman 
3641c6a0718SPierre Ossman 	host->mrq = mrq;
3651c6a0718SPierre Ossman 
3661c6a0718SPierre Ossman 	pxamci_stop_clock(host);
3671c6a0718SPierre Ossman 
3681c6a0718SPierre Ossman 	cmdat = host->cmdat;
3691c6a0718SPierre Ossman 	host->cmdat &= ~CMDAT_INIT;
3701c6a0718SPierre Ossman 
3711c6a0718SPierre Ossman 	if (mrq->data) {
3721c6a0718SPierre Ossman 		pxamci_setup_data(host, mrq->data);
3731c6a0718SPierre Ossman 
3741c6a0718SPierre Ossman 		cmdat &= ~CMDAT_BUSY;
3751c6a0718SPierre Ossman 		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
3761c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_WRITE)
3771c6a0718SPierre Ossman 			cmdat |= CMDAT_WRITE;
3781c6a0718SPierre Ossman 
3791c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_STREAM)
3801c6a0718SPierre Ossman 			cmdat |= CMDAT_STREAM;
3811c6a0718SPierre Ossman 	}
3821c6a0718SPierre Ossman 
3831c6a0718SPierre Ossman 	pxamci_start_cmd(host, mrq->cmd, cmdat);
3841c6a0718SPierre Ossman }
3851c6a0718SPierre Ossman 
3861c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc)
3871c6a0718SPierre Ossman {
3881c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3891c6a0718SPierre Ossman 
3901c6a0718SPierre Ossman 	if (host->pdata && host->pdata->get_ro)
39108f80bb5SAnton Vorontsov 		return !!host->pdata->get_ro(mmc_dev(mmc));
39208f80bb5SAnton Vorontsov 	/*
39308f80bb5SAnton Vorontsov 	 * Board doesn't support read only detection; let the mmc core
39408f80bb5SAnton Vorontsov 	 * decide what to do.
39508f80bb5SAnton Vorontsov 	 */
39608f80bb5SAnton Vorontsov 	return -ENOSYS;
3971c6a0718SPierre Ossman }
3981c6a0718SPierre Ossman 
3991c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
4001c6a0718SPierre Ossman {
4011c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
4021c6a0718SPierre Ossman 
4031c6a0718SPierre Ossman 	if (ios->clock) {
404ebebd9b0SRussell King 		unsigned long rate = host->clkrate;
405ebebd9b0SRussell King 		unsigned int clk = rate / ios->clock;
406ebebd9b0SRussell King 
407d8cb70d1SRussell King 		if (host->clkrt == CLKRT_OFF)
408d8cb70d1SRussell King 			clk_enable(host->clk);
409d8cb70d1SRussell King 
41064eb036aSBridge Wu 		if (ios->clock == 26000000) {
41164eb036aSBridge Wu 			/* to support 26MHz on pxa300/pxa310 */
41264eb036aSBridge Wu 			host->clkrt = 7;
41364eb036aSBridge Wu 		} else {
41464eb036aSBridge Wu 			/* to handle (19.5MHz, 26MHz) */
41564eb036aSBridge Wu 			if (!clk)
41664eb036aSBridge Wu 				clk = 1;
41764eb036aSBridge Wu 
418ebebd9b0SRussell King 			/*
419ebebd9b0SRussell King 			 * clk might result in a lower divisor than we
420ebebd9b0SRussell King 			 * desire.  check for that condition and adjust
421ebebd9b0SRussell King 			 * as appropriate.
422ebebd9b0SRussell King 			 */
423ebebd9b0SRussell King 			if (rate / clk > ios->clock)
4241c6a0718SPierre Ossman 				clk <<= 1;
4251c6a0718SPierre Ossman 			host->clkrt = fls(clk) - 1;
42664eb036aSBridge Wu 		}
4271c6a0718SPierre Ossman 
4281c6a0718SPierre Ossman 		/*
4291c6a0718SPierre Ossman 		 * we write clkrt on the next command
4301c6a0718SPierre Ossman 		 */
4311c6a0718SPierre Ossman 	} else {
4321c6a0718SPierre Ossman 		pxamci_stop_clock(host);
433d8cb70d1SRussell King 		if (host->clkrt != CLKRT_OFF) {
434d8cb70d1SRussell King 			host->clkrt = CLKRT_OFF;
435ebebd9b0SRussell King 			clk_disable(host->clk);
4361c6a0718SPierre Ossman 		}
437d8cb70d1SRussell King 	}
4381c6a0718SPierre Ossman 
4391c6a0718SPierre Ossman 	if (host->power_mode != ios->power_mode) {
4401c6a0718SPierre Ossman 		host->power_mode = ios->power_mode;
4411c6a0718SPierre Ossman 
4421c6a0718SPierre Ossman 		if (host->pdata && host->pdata->setpower)
4431c6a0718SPierre Ossman 			host->pdata->setpower(mmc_dev(mmc), ios->vdd);
4441c6a0718SPierre Ossman 
4451c6a0718SPierre Ossman 		if (ios->power_mode == MMC_POWER_ON)
4461c6a0718SPierre Ossman 			host->cmdat |= CMDAT_INIT;
4471c6a0718SPierre Ossman 	}
4481c6a0718SPierre Ossman 
449df456f47SBridge Wu 	if (ios->bus_width == MMC_BUS_WIDTH_4)
450df456f47SBridge Wu 		host->cmdat |= CMDAT_SD_4DAT;
451df456f47SBridge Wu 	else
452df456f47SBridge Wu 		host->cmdat &= ~CMDAT_SD_4DAT;
453df456f47SBridge Wu 
4541c6a0718SPierre Ossman 	pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
4551c6a0718SPierre Ossman 		 host->clkrt, host->cmdat);
4561c6a0718SPierre Ossman }
4571c6a0718SPierre Ossman 
4585d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
4595d3ad4e8SBridge Wu {
4605d3ad4e8SBridge Wu 	struct pxamci_host *pxa_host = mmc_priv(host);
4615d3ad4e8SBridge Wu 
4625d3ad4e8SBridge Wu 	if (enable)
4635d3ad4e8SBridge Wu 		pxamci_enable_irq(pxa_host, SDIO_INT);
4645d3ad4e8SBridge Wu 	else
4655d3ad4e8SBridge Wu 		pxamci_disable_irq(pxa_host, SDIO_INT);
4665d3ad4e8SBridge Wu }
4675d3ad4e8SBridge Wu 
4681c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = {
4691c6a0718SPierre Ossman 	.request		= pxamci_request,
4701c6a0718SPierre Ossman 	.get_ro			= pxamci_get_ro,
4711c6a0718SPierre Ossman 	.set_ios		= pxamci_set_ios,
4725d3ad4e8SBridge Wu 	.enable_sdio_irq	= pxamci_enable_sdio_irq,
4731c6a0718SPierre Ossman };
4741c6a0718SPierre Ossman 
4751c6a0718SPierre Ossman static void pxamci_dma_irq(int dma, void *devid)
4761c6a0718SPierre Ossman {
477c783837bSNicolas Pitre 	struct pxamci_host *host = devid;
478c783837bSNicolas Pitre 	int dcsr = DCSR(dma);
479c783837bSNicolas Pitre 	DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
480c783837bSNicolas Pitre 
481c783837bSNicolas Pitre 	if (dcsr & DCSR_ENDINTR) {
482c783837bSNicolas Pitre 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
483c783837bSNicolas Pitre 	} else {
484c783837bSNicolas Pitre 		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
485c783837bSNicolas Pitre 		       mmc_hostname(host->mmc), dma, dcsr);
486c783837bSNicolas Pitre 		host->data->error = -EIO;
487c783837bSNicolas Pitre 		pxamci_data_done(host, 0);
488c783837bSNicolas Pitre 	}
4891c6a0718SPierre Ossman }
4901c6a0718SPierre Ossman 
4911c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid)
4921c6a0718SPierre Ossman {
4931c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(devid);
4941c6a0718SPierre Ossman 
4951c6a0718SPierre Ossman 	mmc_detect_change(devid, host->pdata->detect_delay);
4961c6a0718SPierre Ossman 	return IRQ_HANDLED;
4971c6a0718SPierre Ossman }
4981c6a0718SPierre Ossman 
4991c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev)
5001c6a0718SPierre Ossman {
5011c6a0718SPierre Ossman 	struct mmc_host *mmc;
5021c6a0718SPierre Ossman 	struct pxamci_host *host = NULL;
5039a788c6bSBridge Wu 	struct resource *r, *dmarx, *dmatx;
5041c6a0718SPierre Ossman 	int ret, irq;
5051c6a0718SPierre Ossman 
5061c6a0718SPierre Ossman 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5071c6a0718SPierre Ossman 	irq = platform_get_irq(pdev, 0);
5081c6a0718SPierre Ossman 	if (!r || irq < 0)
5091c6a0718SPierre Ossman 		return -ENXIO;
5101c6a0718SPierre Ossman 
5111c6a0718SPierre Ossman 	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
5121c6a0718SPierre Ossman 	if (!r)
5131c6a0718SPierre Ossman 		return -EBUSY;
5141c6a0718SPierre Ossman 
5151c6a0718SPierre Ossman 	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
5161c6a0718SPierre Ossman 	if (!mmc) {
5171c6a0718SPierre Ossman 		ret = -ENOMEM;
5181c6a0718SPierre Ossman 		goto out;
5191c6a0718SPierre Ossman 	}
5201c6a0718SPierre Ossman 
5211c6a0718SPierre Ossman 	mmc->ops = &pxamci_ops;
5221c6a0718SPierre Ossman 
5231c6a0718SPierre Ossman 	/*
5241c6a0718SPierre Ossman 	 * We can do SG-DMA, but we don't because we never know how much
5251c6a0718SPierre Ossman 	 * data we successfully wrote to the card.
5261c6a0718SPierre Ossman 	 */
5271c6a0718SPierre Ossman 	mmc->max_phys_segs = NR_SG;
5281c6a0718SPierre Ossman 
5291c6a0718SPierre Ossman 	/*
5301c6a0718SPierre Ossman 	 * Our hardware DMA can handle a maximum of one page per SG entry.
5311c6a0718SPierre Ossman 	 */
5321c6a0718SPierre Ossman 	mmc->max_seg_size = PAGE_SIZE;
5331c6a0718SPierre Ossman 
5341c6a0718SPierre Ossman 	/*
535fe2dc44eSNicolas Pitre 	 * Block length register is only 10 bits before PXA27x.
5361c6a0718SPierre Ossman 	 */
5370ffcbfd5SEric Miao 	mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048;
5381c6a0718SPierre Ossman 
5391c6a0718SPierre Ossman 	/*
5401c6a0718SPierre Ossman 	 * Block count register is 16 bits.
5411c6a0718SPierre Ossman 	 */
5421c6a0718SPierre Ossman 	mmc->max_blk_count = 65535;
5431c6a0718SPierre Ossman 
5441c6a0718SPierre Ossman 	host = mmc_priv(mmc);
5451c6a0718SPierre Ossman 	host->mmc = mmc;
5461c6a0718SPierre Ossman 	host->dma = -1;
5471c6a0718SPierre Ossman 	host->pdata = pdev->dev.platform_data;
548d8cb70d1SRussell King 	host->clkrt = CLKRT_OFF;
549ebebd9b0SRussell King 
550e0d8b13aSRussell King 	host->clk = clk_get(&pdev->dev, NULL);
551ebebd9b0SRussell King 	if (IS_ERR(host->clk)) {
552ebebd9b0SRussell King 		ret = PTR_ERR(host->clk);
553ebebd9b0SRussell King 		host->clk = NULL;
554ebebd9b0SRussell King 		goto out;
555ebebd9b0SRussell King 	}
556ebebd9b0SRussell King 
557ebebd9b0SRussell King 	host->clkrate = clk_get_rate(host->clk);
558ebebd9b0SRussell King 
559ebebd9b0SRussell King 	/*
560ebebd9b0SRussell King 	 * Calculate minimum clock rate, rounding up.
561ebebd9b0SRussell King 	 */
562ebebd9b0SRussell King 	mmc->f_min = (host->clkrate + 63) / 64;
56364eb036aSBridge Wu 	mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000
56464eb036aSBridge Wu 							  : host->clkrate;
565ebebd9b0SRussell King 
5661c6a0718SPierre Ossman 	mmc->ocr_avail = host->pdata ?
5671c6a0718SPierre Ossman 			 host->pdata->ocr_mask :
5681c6a0718SPierre Ossman 			 MMC_VDD_32_33|MMC_VDD_33_34;
569df456f47SBridge Wu 	mmc->caps = 0;
5705d3ad4e8SBridge Wu 	host->cmdat = 0;
5710ffcbfd5SEric Miao 	if (!cpu_is_pxa25x()) {
5725d3ad4e8SBridge Wu 		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
5735d3ad4e8SBridge Wu 		host->cmdat |= CMDAT_SDIO_INT_EN;
57464eb036aSBridge Wu 		if (cpu_is_pxa300() || cpu_is_pxa310())
57564eb036aSBridge Wu 			mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
57664eb036aSBridge Wu 				     MMC_CAP_SD_HIGHSPEED;
5775d3ad4e8SBridge Wu 	}
5781c6a0718SPierre Ossman 
5791c6a0718SPierre Ossman 	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
5801c6a0718SPierre Ossman 	if (!host->sg_cpu) {
5811c6a0718SPierre Ossman 		ret = -ENOMEM;
5821c6a0718SPierre Ossman 		goto out;
5831c6a0718SPierre Ossman 	}
5841c6a0718SPierre Ossman 
5851c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
5861c6a0718SPierre Ossman 	host->res = r;
5871c6a0718SPierre Ossman 	host->irq = irq;
5881c6a0718SPierre Ossman 	host->imask = MMC_I_MASK_ALL;
5891c6a0718SPierre Ossman 
5901c6a0718SPierre Ossman 	host->base = ioremap(r->start, SZ_4K);
5911c6a0718SPierre Ossman 	if (!host->base) {
5921c6a0718SPierre Ossman 		ret = -ENOMEM;
5931c6a0718SPierre Ossman 		goto out;
5941c6a0718SPierre Ossman 	}
5951c6a0718SPierre Ossman 
5961c6a0718SPierre Ossman 	/*
5971c6a0718SPierre Ossman 	 * Ensure that the host controller is shut down, and setup
5981c6a0718SPierre Ossman 	 * with our defaults.
5991c6a0718SPierre Ossman 	 */
6001c6a0718SPierre Ossman 	pxamci_stop_clock(host);
6011c6a0718SPierre Ossman 	writel(0, host->base + MMC_SPI);
6021c6a0718SPierre Ossman 	writel(64, host->base + MMC_RESTO);
6031c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
6041c6a0718SPierre Ossman 
6051c6a0718SPierre Ossman 	host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
6061c6a0718SPierre Ossman 				    pxamci_dma_irq, host);
6071c6a0718SPierre Ossman 	if (host->dma < 0) {
6081c6a0718SPierre Ossman 		ret = -EBUSY;
6091c6a0718SPierre Ossman 		goto out;
6101c6a0718SPierre Ossman 	}
6111c6a0718SPierre Ossman 
6121c6a0718SPierre Ossman 	ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
6131c6a0718SPierre Ossman 	if (ret)
6141c6a0718SPierre Ossman 		goto out;
6151c6a0718SPierre Ossman 
6161c6a0718SPierre Ossman 	platform_set_drvdata(pdev, mmc);
6171c6a0718SPierre Ossman 
6189a788c6bSBridge Wu 	dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
6199a788c6bSBridge Wu 	if (!dmarx) {
6209a788c6bSBridge Wu 		ret = -ENXIO;
6219a788c6bSBridge Wu 		goto out;
6229a788c6bSBridge Wu 	}
6239a788c6bSBridge Wu 	host->dma_drcmrrx = dmarx->start;
6249a788c6bSBridge Wu 
6259a788c6bSBridge Wu 	dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
6269a788c6bSBridge Wu 	if (!dmatx) {
6279a788c6bSBridge Wu 		ret = -ENXIO;
6289a788c6bSBridge Wu 		goto out;
6299a788c6bSBridge Wu 	}
6309a788c6bSBridge Wu 	host->dma_drcmrtx = dmatx->start;
6319a788c6bSBridge Wu 
6321c6a0718SPierre Ossman 	if (host->pdata && host->pdata->init)
6331c6a0718SPierre Ossman 		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
6341c6a0718SPierre Ossman 
6351c6a0718SPierre Ossman 	mmc_add_host(mmc);
6361c6a0718SPierre Ossman 
6371c6a0718SPierre Ossman 	return 0;
6381c6a0718SPierre Ossman 
6391c6a0718SPierre Ossman  out:
6401c6a0718SPierre Ossman 	if (host) {
6411c6a0718SPierre Ossman 		if (host->dma >= 0)
6421c6a0718SPierre Ossman 			pxa_free_dma(host->dma);
6431c6a0718SPierre Ossman 		if (host->base)
6441c6a0718SPierre Ossman 			iounmap(host->base);
6451c6a0718SPierre Ossman 		if (host->sg_cpu)
6461c6a0718SPierre Ossman 			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
647ebebd9b0SRussell King 		if (host->clk)
648ebebd9b0SRussell King 			clk_put(host->clk);
6491c6a0718SPierre Ossman 	}
6501c6a0718SPierre Ossman 	if (mmc)
6511c6a0718SPierre Ossman 		mmc_free_host(mmc);
6521c6a0718SPierre Ossman 	release_resource(r);
6531c6a0718SPierre Ossman 	return ret;
6541c6a0718SPierre Ossman }
6551c6a0718SPierre Ossman 
6561c6a0718SPierre Ossman static int pxamci_remove(struct platform_device *pdev)
6571c6a0718SPierre Ossman {
6581c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(pdev);
6591c6a0718SPierre Ossman 
6601c6a0718SPierre Ossman 	platform_set_drvdata(pdev, NULL);
6611c6a0718SPierre Ossman 
6621c6a0718SPierre Ossman 	if (mmc) {
6631c6a0718SPierre Ossman 		struct pxamci_host *host = mmc_priv(mmc);
6641c6a0718SPierre Ossman 
6651c6a0718SPierre Ossman 		if (host->pdata && host->pdata->exit)
6661c6a0718SPierre Ossman 			host->pdata->exit(&pdev->dev, mmc);
6671c6a0718SPierre Ossman 
6681c6a0718SPierre Ossman 		mmc_remove_host(mmc);
6691c6a0718SPierre Ossman 
6701c6a0718SPierre Ossman 		pxamci_stop_clock(host);
6711c6a0718SPierre Ossman 		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
6721c6a0718SPierre Ossman 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
6731c6a0718SPierre Ossman 		       host->base + MMC_I_MASK);
6741c6a0718SPierre Ossman 
6759a788c6bSBridge Wu 		DRCMR(host->dma_drcmrrx) = 0;
6769a788c6bSBridge Wu 		DRCMR(host->dma_drcmrtx) = 0;
6771c6a0718SPierre Ossman 
6781c6a0718SPierre Ossman 		free_irq(host->irq, host);
6791c6a0718SPierre Ossman 		pxa_free_dma(host->dma);
6801c6a0718SPierre Ossman 		iounmap(host->base);
6811c6a0718SPierre Ossman 		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
6821c6a0718SPierre Ossman 
683ebebd9b0SRussell King 		clk_put(host->clk);
684ebebd9b0SRussell King 
6851c6a0718SPierre Ossman 		release_resource(host->res);
6861c6a0718SPierre Ossman 
6871c6a0718SPierre Ossman 		mmc_free_host(mmc);
6881c6a0718SPierre Ossman 	}
6891c6a0718SPierre Ossman 	return 0;
6901c6a0718SPierre Ossman }
6911c6a0718SPierre Ossman 
6921c6a0718SPierre Ossman #ifdef CONFIG_PM
6931c6a0718SPierre Ossman static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
6941c6a0718SPierre Ossman {
6951c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(dev);
6961c6a0718SPierre Ossman 	int ret = 0;
6971c6a0718SPierre Ossman 
6981c6a0718SPierre Ossman 	if (mmc)
6991c6a0718SPierre Ossman 		ret = mmc_suspend_host(mmc, state);
7001c6a0718SPierre Ossman 
7011c6a0718SPierre Ossman 	return ret;
7021c6a0718SPierre Ossman }
7031c6a0718SPierre Ossman 
7041c6a0718SPierre Ossman static int pxamci_resume(struct platform_device *dev)
7051c6a0718SPierre Ossman {
7061c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(dev);
7071c6a0718SPierre Ossman 	int ret = 0;
7081c6a0718SPierre Ossman 
7091c6a0718SPierre Ossman 	if (mmc)
7101c6a0718SPierre Ossman 		ret = mmc_resume_host(mmc);
7111c6a0718SPierre Ossman 
7121c6a0718SPierre Ossman 	return ret;
7131c6a0718SPierre Ossman }
7141c6a0718SPierre Ossman #else
7151c6a0718SPierre Ossman #define pxamci_suspend	NULL
7161c6a0718SPierre Ossman #define pxamci_resume	NULL
7171c6a0718SPierre Ossman #endif
7181c6a0718SPierre Ossman 
7191c6a0718SPierre Ossman static struct platform_driver pxamci_driver = {
7201c6a0718SPierre Ossman 	.probe		= pxamci_probe,
7211c6a0718SPierre Ossman 	.remove		= pxamci_remove,
7221c6a0718SPierre Ossman 	.suspend	= pxamci_suspend,
7231c6a0718SPierre Ossman 	.resume		= pxamci_resume,
7241c6a0718SPierre Ossman 	.driver		= {
7251c6a0718SPierre Ossman 		.name	= DRIVER_NAME,
726bc65c724SKay Sievers 		.owner	= THIS_MODULE,
7271c6a0718SPierre Ossman 	},
7281c6a0718SPierre Ossman };
7291c6a0718SPierre Ossman 
7301c6a0718SPierre Ossman static int __init pxamci_init(void)
7311c6a0718SPierre Ossman {
7321c6a0718SPierre Ossman 	return platform_driver_register(&pxamci_driver);
7331c6a0718SPierre Ossman }
7341c6a0718SPierre Ossman 
7351c6a0718SPierre Ossman static void __exit pxamci_exit(void)
7361c6a0718SPierre Ossman {
7371c6a0718SPierre Ossman 	platform_driver_unregister(&pxamci_driver);
7381c6a0718SPierre Ossman }
7391c6a0718SPierre Ossman 
7401c6a0718SPierre Ossman module_init(pxamci_init);
7411c6a0718SPierre Ossman module_exit(pxamci_exit);
7421c6a0718SPierre Ossman 
7431c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
7441c6a0718SPierre Ossman MODULE_LICENSE("GPL");
745bc65c724SKay Sievers MODULE_ALIAS("platform:pxa2xx-mci");
746