xref: /openbmc/linux/drivers/mmc/host/pxamci.c (revision 70f10482)
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>
261c6a0718SPierre Ossman #include <linux/mmc/host.h>
271c6a0718SPierre Ossman 
281c6a0718SPierre Ossman #include <asm/dma.h>
291c6a0718SPierre Ossman #include <asm/io.h>
301c6a0718SPierre Ossman #include <asm/scatterlist.h>
311c6a0718SPierre Ossman #include <asm/sizes.h>
321c6a0718SPierre Ossman 
331c6a0718SPierre Ossman #include <asm/arch/pxa-regs.h>
341c6a0718SPierre Ossman #include <asm/arch/mmc.h>
351c6a0718SPierre Ossman 
361c6a0718SPierre Ossman #include "pxamci.h"
371c6a0718SPierre Ossman 
381c6a0718SPierre Ossman #define DRIVER_NAME	"pxa2xx-mci"
391c6a0718SPierre Ossman 
401c6a0718SPierre Ossman #define NR_SG	1
411c6a0718SPierre Ossman 
421c6a0718SPierre Ossman struct pxamci_host {
431c6a0718SPierre Ossman 	struct mmc_host		*mmc;
441c6a0718SPierre Ossman 	spinlock_t		lock;
451c6a0718SPierre Ossman 	struct resource		*res;
461c6a0718SPierre Ossman 	void __iomem		*base;
471c6a0718SPierre Ossman 	int			irq;
481c6a0718SPierre Ossman 	int			dma;
491c6a0718SPierre Ossman 	unsigned int		clkrt;
501c6a0718SPierre Ossman 	unsigned int		cmdat;
511c6a0718SPierre Ossman 	unsigned int		imask;
521c6a0718SPierre Ossman 	unsigned int		power_mode;
531c6a0718SPierre Ossman 	struct pxamci_platform_data *pdata;
541c6a0718SPierre Ossman 
551c6a0718SPierre Ossman 	struct mmc_request	*mrq;
561c6a0718SPierre Ossman 	struct mmc_command	*cmd;
571c6a0718SPierre Ossman 	struct mmc_data		*data;
581c6a0718SPierre Ossman 
591c6a0718SPierre Ossman 	dma_addr_t		sg_dma;
601c6a0718SPierre Ossman 	struct pxa_dma_desc	*sg_cpu;
611c6a0718SPierre Ossman 	unsigned int		dma_len;
621c6a0718SPierre Ossman 
631c6a0718SPierre Ossman 	unsigned int		dma_dir;
641c6a0718SPierre Ossman };
651c6a0718SPierre Ossman 
661c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host)
671c6a0718SPierre Ossman {
681c6a0718SPierre Ossman 	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
691c6a0718SPierre Ossman 		unsigned long timeout = 10000;
701c6a0718SPierre Ossman 		unsigned int v;
711c6a0718SPierre Ossman 
721c6a0718SPierre Ossman 		writel(STOP_CLOCK, host->base + MMC_STRPCL);
731c6a0718SPierre Ossman 
741c6a0718SPierre Ossman 		do {
751c6a0718SPierre Ossman 			v = readl(host->base + MMC_STAT);
761c6a0718SPierre Ossman 			if (!(v & STAT_CLK_EN))
771c6a0718SPierre Ossman 				break;
781c6a0718SPierre Ossman 			udelay(1);
791c6a0718SPierre Ossman 		} while (timeout--);
801c6a0718SPierre Ossman 
811c6a0718SPierre Ossman 		if (v & STAT_CLK_EN)
821c6a0718SPierre Ossman 			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
831c6a0718SPierre Ossman 	}
841c6a0718SPierre Ossman }
851c6a0718SPierre Ossman 
861c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
871c6a0718SPierre Ossman {
881c6a0718SPierre Ossman 	unsigned long flags;
891c6a0718SPierre Ossman 
901c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
911c6a0718SPierre Ossman 	host->imask &= ~mask;
921c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
931c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
941c6a0718SPierre Ossman }
951c6a0718SPierre Ossman 
961c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
971c6a0718SPierre Ossman {
981c6a0718SPierre Ossman 	unsigned long flags;
991c6a0718SPierre Ossman 
1001c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
1011c6a0718SPierre Ossman 	host->imask |= mask;
1021c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1031c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1041c6a0718SPierre Ossman }
1051c6a0718SPierre Ossman 
1061c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
1071c6a0718SPierre Ossman {
1081c6a0718SPierre Ossman 	unsigned int nob = data->blocks;
1091c6a0718SPierre Ossman 	unsigned long long clks;
1101c6a0718SPierre Ossman 	unsigned int timeout;
1111c6a0718SPierre Ossman 	u32 dcmd;
1121c6a0718SPierre Ossman 	int i;
1131c6a0718SPierre Ossman 
1141c6a0718SPierre Ossman 	host->data = data;
1151c6a0718SPierre Ossman 
1161c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_STREAM)
1171c6a0718SPierre Ossman 		nob = 0xffff;
1181c6a0718SPierre Ossman 
1191c6a0718SPierre Ossman 	writel(nob, host->base + MMC_NOB);
1201c6a0718SPierre Ossman 	writel(data->blksz, host->base + MMC_BLKLEN);
1211c6a0718SPierre Ossman 
1221c6a0718SPierre Ossman 	clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
1231c6a0718SPierre Ossman 	do_div(clks, 1000000000UL);
1241c6a0718SPierre Ossman 	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
1251c6a0718SPierre Ossman 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
1261c6a0718SPierre Ossman 
1271c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ) {
1281c6a0718SPierre Ossman 		host->dma_dir = DMA_FROM_DEVICE;
1291c6a0718SPierre Ossman 		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
1301c6a0718SPierre Ossman 		DRCMRTXMMC = 0;
1311c6a0718SPierre Ossman 		DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
1321c6a0718SPierre Ossman 	} else {
1331c6a0718SPierre Ossman 		host->dma_dir = DMA_TO_DEVICE;
1341c6a0718SPierre Ossman 		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
1351c6a0718SPierre Ossman 		DRCMRRXMMC = 0;
1361c6a0718SPierre Ossman 		DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
1371c6a0718SPierre Ossman 	}
1381c6a0718SPierre Ossman 
1391c6a0718SPierre Ossman 	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
1401c6a0718SPierre Ossman 
1411c6a0718SPierre Ossman 	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1421c6a0718SPierre Ossman 				   host->dma_dir);
1431c6a0718SPierre Ossman 
1441c6a0718SPierre Ossman 	for (i = 0; i < host->dma_len; i++) {
1451c6a0718SPierre Ossman 		if (data->flags & MMC_DATA_READ) {
1461c6a0718SPierre Ossman 			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
1471c6a0718SPierre Ossman 			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
1481c6a0718SPierre Ossman 		} else {
1491c6a0718SPierre Ossman 			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
1501c6a0718SPierre Ossman 			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
1511c6a0718SPierre Ossman 		}
1521c6a0718SPierre Ossman 		host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
1531c6a0718SPierre Ossman 		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
1541c6a0718SPierre Ossman 					sizeof(struct pxa_dma_desc);
1551c6a0718SPierre Ossman 	}
1561c6a0718SPierre Ossman 	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
1571c6a0718SPierre Ossman 	wmb();
1581c6a0718SPierre Ossman 
1591c6a0718SPierre Ossman 	DDADR(host->dma) = host->sg_dma;
1601c6a0718SPierre Ossman 	DCSR(host->dma) = DCSR_RUN;
1611c6a0718SPierre Ossman }
1621c6a0718SPierre Ossman 
1631c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
1641c6a0718SPierre Ossman {
1651c6a0718SPierre Ossman 	WARN_ON(host->cmd != NULL);
1661c6a0718SPierre Ossman 	host->cmd = cmd;
1671c6a0718SPierre Ossman 
1681c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_BUSY)
1691c6a0718SPierre Ossman 		cmdat |= CMDAT_BUSY;
1701c6a0718SPierre Ossman 
1711c6a0718SPierre Ossman #define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
1721c6a0718SPierre Ossman 	switch (RSP_TYPE(mmc_resp_type(cmd))) {
1731c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
1741c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_SHORT;
1751c6a0718SPierre Ossman 		break;
1761c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R3):
1771c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R3;
1781c6a0718SPierre Ossman 		break;
1791c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R2):
1801c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R2;
1811c6a0718SPierre Ossman 		break;
1821c6a0718SPierre Ossman 	default:
1831c6a0718SPierre Ossman 		break;
1841c6a0718SPierre Ossman 	}
1851c6a0718SPierre Ossman 
1861c6a0718SPierre Ossman 	writel(cmd->opcode, host->base + MMC_CMD);
1871c6a0718SPierre Ossman 	writel(cmd->arg >> 16, host->base + MMC_ARGH);
1881c6a0718SPierre Ossman 	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
1891c6a0718SPierre Ossman 	writel(cmdat, host->base + MMC_CMDAT);
1901c6a0718SPierre Ossman 	writel(host->clkrt, host->base + MMC_CLKRT);
1911c6a0718SPierre Ossman 
1921c6a0718SPierre Ossman 	writel(START_CLOCK, host->base + MMC_STRPCL);
1931c6a0718SPierre Ossman 
1941c6a0718SPierre Ossman 	pxamci_enable_irq(host, END_CMD_RES);
1951c6a0718SPierre Ossman }
1961c6a0718SPierre Ossman 
1971c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
1981c6a0718SPierre Ossman {
1991c6a0718SPierre Ossman 	host->mrq = NULL;
2001c6a0718SPierre Ossman 	host->cmd = NULL;
2011c6a0718SPierre Ossman 	host->data = NULL;
2021c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
2031c6a0718SPierre Ossman }
2041c6a0718SPierre Ossman 
2051c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
2061c6a0718SPierre Ossman {
2071c6a0718SPierre Ossman 	struct mmc_command *cmd = host->cmd;
2081c6a0718SPierre Ossman 	int i;
2091c6a0718SPierre Ossman 	u32 v;
2101c6a0718SPierre Ossman 
2111c6a0718SPierre Ossman 	if (!cmd)
2121c6a0718SPierre Ossman 		return 0;
2131c6a0718SPierre Ossman 
2141c6a0718SPierre Ossman 	host->cmd = NULL;
2151c6a0718SPierre Ossman 
2161c6a0718SPierre Ossman 	/*
2171c6a0718SPierre Ossman 	 * Did I mention this is Sick.  We always need to
2181c6a0718SPierre Ossman 	 * discard the upper 8 bits of the first 16-bit word.
2191c6a0718SPierre Ossman 	 */
2201c6a0718SPierre Ossman 	v = readl(host->base + MMC_RES) & 0xffff;
2211c6a0718SPierre Ossman 	for (i = 0; i < 4; i++) {
2221c6a0718SPierre Ossman 		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
2231c6a0718SPierre Ossman 		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
2241c6a0718SPierre Ossman 		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
2251c6a0718SPierre Ossman 		v = w2;
2261c6a0718SPierre Ossman 	}
2271c6a0718SPierre Ossman 
2281c6a0718SPierre Ossman 	if (stat & STAT_TIME_OUT_RESPONSE) {
2291c6a0718SPierre Ossman 		cmd->error = MMC_ERR_TIMEOUT;
2301c6a0718SPierre Ossman 	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
2311c6a0718SPierre Ossman #ifdef CONFIG_PXA27x
2321c6a0718SPierre Ossman 		/*
2331c6a0718SPierre Ossman 		 * workaround for erratum #42:
2341c6a0718SPierre Ossman 		 * Intel PXA27x Family Processor Specification Update Rev 001
23590e07d9fSNicolas Pitre 		 * A bogus CRC error can appear if the msb of a 136 bit
23690e07d9fSNicolas Pitre 		 * response is a one.
2371c6a0718SPierre Ossman 		 */
23890e07d9fSNicolas Pitre 		if (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000) {
2391c6a0718SPierre Ossman 			pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
24090e07d9fSNicolas Pitre 		} else
2411c6a0718SPierre Ossman #endif
24290e07d9fSNicolas Pitre 		cmd->error = MMC_ERR_BADCRC;
2431c6a0718SPierre Ossman 	}
2441c6a0718SPierre Ossman 
2451c6a0718SPierre Ossman 	pxamci_disable_irq(host, END_CMD_RES);
2461c6a0718SPierre Ossman 	if (host->data && cmd->error == MMC_ERR_NONE) {
2471c6a0718SPierre Ossman 		pxamci_enable_irq(host, DATA_TRAN_DONE);
2481c6a0718SPierre Ossman 	} else {
2491c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
2501c6a0718SPierre Ossman 	}
2511c6a0718SPierre Ossman 
2521c6a0718SPierre Ossman 	return 1;
2531c6a0718SPierre Ossman }
2541c6a0718SPierre Ossman 
2551c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
2561c6a0718SPierre Ossman {
2571c6a0718SPierre Ossman 	struct mmc_data *data = host->data;
2581c6a0718SPierre Ossman 
2591c6a0718SPierre Ossman 	if (!data)
2601c6a0718SPierre Ossman 		return 0;
2611c6a0718SPierre Ossman 
2621c6a0718SPierre Ossman 	DCSR(host->dma) = 0;
2631c6a0718SPierre Ossman 	dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
2641c6a0718SPierre Ossman 		     host->dma_dir);
2651c6a0718SPierre Ossman 
2661c6a0718SPierre Ossman 	if (stat & STAT_READ_TIME_OUT)
2671c6a0718SPierre Ossman 		data->error = MMC_ERR_TIMEOUT;
2681c6a0718SPierre Ossman 	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
2691c6a0718SPierre Ossman 		data->error = MMC_ERR_BADCRC;
2701c6a0718SPierre Ossman 
2711c6a0718SPierre Ossman 	/*
2721c6a0718SPierre Ossman 	 * There appears to be a hardware design bug here.  There seems to
2731c6a0718SPierre Ossman 	 * be no way to find out how much data was transferred to the card.
2741c6a0718SPierre Ossman 	 * This means that if there was an error on any block, we mark all
2751c6a0718SPierre Ossman 	 * data blocks as being in error.
2761c6a0718SPierre Ossman 	 */
2771c6a0718SPierre Ossman 	if (data->error == MMC_ERR_NONE)
2781c6a0718SPierre Ossman 		data->bytes_xfered = data->blocks * data->blksz;
2791c6a0718SPierre Ossman 	else
2801c6a0718SPierre Ossman 		data->bytes_xfered = 0;
2811c6a0718SPierre Ossman 
2821c6a0718SPierre Ossman 	pxamci_disable_irq(host, DATA_TRAN_DONE);
2831c6a0718SPierre Ossman 
2841c6a0718SPierre Ossman 	host->data = NULL;
2851c6a0718SPierre Ossman 	if (host->mrq->stop) {
2861c6a0718SPierre Ossman 		pxamci_stop_clock(host);
2871c6a0718SPierre Ossman 		pxamci_start_cmd(host, host->mrq->stop, 0);
2881c6a0718SPierre Ossman 	} else {
2891c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
2901c6a0718SPierre Ossman 	}
2911c6a0718SPierre Ossman 
2921c6a0718SPierre Ossman 	return 1;
2931c6a0718SPierre Ossman }
2941c6a0718SPierre Ossman 
2951c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid)
2961c6a0718SPierre Ossman {
2971c6a0718SPierre Ossman 	struct pxamci_host *host = devid;
2981c6a0718SPierre Ossman 	unsigned int ireg;
2991c6a0718SPierre Ossman 	int handled = 0;
3001c6a0718SPierre Ossman 
3011c6a0718SPierre Ossman 	ireg = readl(host->base + MMC_I_REG);
3021c6a0718SPierre Ossman 
3031c6a0718SPierre Ossman 	if (ireg) {
3041c6a0718SPierre Ossman 		unsigned stat = readl(host->base + MMC_STAT);
3051c6a0718SPierre Ossman 
3061c6a0718SPierre Ossman 		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
3071c6a0718SPierre Ossman 
3081c6a0718SPierre Ossman 		if (ireg & END_CMD_RES)
3091c6a0718SPierre Ossman 			handled |= pxamci_cmd_done(host, stat);
3101c6a0718SPierre Ossman 		if (ireg & DATA_TRAN_DONE)
3111c6a0718SPierre Ossman 			handled |= pxamci_data_done(host, stat);
3121c6a0718SPierre Ossman 	}
3131c6a0718SPierre Ossman 
3141c6a0718SPierre Ossman 	return IRQ_RETVAL(handled);
3151c6a0718SPierre Ossman }
3161c6a0718SPierre Ossman 
3171c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
3181c6a0718SPierre Ossman {
3191c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3201c6a0718SPierre Ossman 	unsigned int cmdat;
3211c6a0718SPierre Ossman 
3221c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
3231c6a0718SPierre Ossman 
3241c6a0718SPierre Ossman 	host->mrq = mrq;
3251c6a0718SPierre Ossman 
3261c6a0718SPierre Ossman 	pxamci_stop_clock(host);
3271c6a0718SPierre Ossman 
3281c6a0718SPierre Ossman 	cmdat = host->cmdat;
3291c6a0718SPierre Ossman 	host->cmdat &= ~CMDAT_INIT;
3301c6a0718SPierre Ossman 
3311c6a0718SPierre Ossman 	if (mrq->data) {
3321c6a0718SPierre Ossman 		pxamci_setup_data(host, mrq->data);
3331c6a0718SPierre Ossman 
3341c6a0718SPierre Ossman 		cmdat &= ~CMDAT_BUSY;
3351c6a0718SPierre Ossman 		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
3361c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_WRITE)
3371c6a0718SPierre Ossman 			cmdat |= CMDAT_WRITE;
3381c6a0718SPierre Ossman 
3391c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_STREAM)
3401c6a0718SPierre Ossman 			cmdat |= CMDAT_STREAM;
3411c6a0718SPierre Ossman 	}
3421c6a0718SPierre Ossman 
3431c6a0718SPierre Ossman 	pxamci_start_cmd(host, mrq->cmd, cmdat);
3441c6a0718SPierre Ossman }
3451c6a0718SPierre Ossman 
3461c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc)
3471c6a0718SPierre Ossman {
3481c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3491c6a0718SPierre Ossman 
3501c6a0718SPierre Ossman 	if (host->pdata && host->pdata->get_ro)
3511c6a0718SPierre Ossman 		return host->pdata->get_ro(mmc_dev(mmc));
3521c6a0718SPierre Ossman 	/* Host doesn't support read only detection so assume writeable */
3531c6a0718SPierre Ossman 	return 0;
3541c6a0718SPierre Ossman }
3551c6a0718SPierre Ossman 
3561c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
3571c6a0718SPierre Ossman {
3581c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
3591c6a0718SPierre Ossman 
3601c6a0718SPierre Ossman 	if (ios->clock) {
3611c6a0718SPierre Ossman 		unsigned int clk = CLOCKRATE / ios->clock;
3621c6a0718SPierre Ossman 		if (CLOCKRATE / clk > ios->clock)
3631c6a0718SPierre Ossman 			clk <<= 1;
3641c6a0718SPierre Ossman 		host->clkrt = fls(clk) - 1;
365c6799adeSLinus Torvalds 		pxa_set_cken(CKEN_MMC, 1);
3661c6a0718SPierre Ossman 
3671c6a0718SPierre Ossman 		/*
3681c6a0718SPierre Ossman 		 * we write clkrt on the next command
3691c6a0718SPierre Ossman 		 */
3701c6a0718SPierre Ossman 	} else {
3711c6a0718SPierre Ossman 		pxamci_stop_clock(host);
372c6799adeSLinus Torvalds 		pxa_set_cken(CKEN_MMC, 0);
3731c6a0718SPierre Ossman 	}
3741c6a0718SPierre Ossman 
3751c6a0718SPierre Ossman 	if (host->power_mode != ios->power_mode) {
3761c6a0718SPierre Ossman 		host->power_mode = ios->power_mode;
3771c6a0718SPierre Ossman 
3781c6a0718SPierre Ossman 		if (host->pdata && host->pdata->setpower)
3791c6a0718SPierre Ossman 			host->pdata->setpower(mmc_dev(mmc), ios->vdd);
3801c6a0718SPierre Ossman 
3811c6a0718SPierre Ossman 		if (ios->power_mode == MMC_POWER_ON)
3821c6a0718SPierre Ossman 			host->cmdat |= CMDAT_INIT;
3831c6a0718SPierre Ossman 	}
3841c6a0718SPierre Ossman 
3851c6a0718SPierre Ossman 	pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
3861c6a0718SPierre Ossman 		 host->clkrt, host->cmdat);
3871c6a0718SPierre Ossman }
3881c6a0718SPierre Ossman 
3891c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = {
3901c6a0718SPierre Ossman 	.request	= pxamci_request,
3911c6a0718SPierre Ossman 	.get_ro		= pxamci_get_ro,
3921c6a0718SPierre Ossman 	.set_ios	= pxamci_set_ios,
3931c6a0718SPierre Ossman };
3941c6a0718SPierre Ossman 
3951c6a0718SPierre Ossman static void pxamci_dma_irq(int dma, void *devid)
3961c6a0718SPierre Ossman {
3971c6a0718SPierre Ossman 	printk(KERN_ERR "DMA%d: IRQ???\n", dma);
3981c6a0718SPierre Ossman 	DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
3991c6a0718SPierre Ossman }
4001c6a0718SPierre Ossman 
4011c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid)
4021c6a0718SPierre Ossman {
4031c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(devid);
4041c6a0718SPierre Ossman 
4051c6a0718SPierre Ossman 	mmc_detect_change(devid, host->pdata->detect_delay);
4061c6a0718SPierre Ossman 	return IRQ_HANDLED;
4071c6a0718SPierre Ossman }
4081c6a0718SPierre Ossman 
4091c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev)
4101c6a0718SPierre Ossman {
4111c6a0718SPierre Ossman 	struct mmc_host *mmc;
4121c6a0718SPierre Ossman 	struct pxamci_host *host = NULL;
4131c6a0718SPierre Ossman 	struct resource *r;
4141c6a0718SPierre Ossman 	int ret, irq;
4151c6a0718SPierre Ossman 
4161c6a0718SPierre Ossman 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4171c6a0718SPierre Ossman 	irq = platform_get_irq(pdev, 0);
4181c6a0718SPierre Ossman 	if (!r || irq < 0)
4191c6a0718SPierre Ossman 		return -ENXIO;
4201c6a0718SPierre Ossman 
4211c6a0718SPierre Ossman 	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
4221c6a0718SPierre Ossman 	if (!r)
4231c6a0718SPierre Ossman 		return -EBUSY;
4241c6a0718SPierre Ossman 
4251c6a0718SPierre Ossman 	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
4261c6a0718SPierre Ossman 	if (!mmc) {
4271c6a0718SPierre Ossman 		ret = -ENOMEM;
4281c6a0718SPierre Ossman 		goto out;
4291c6a0718SPierre Ossman 	}
4301c6a0718SPierre Ossman 
4311c6a0718SPierre Ossman 	mmc->ops = &pxamci_ops;
4321c6a0718SPierre Ossman 	mmc->f_min = CLOCKRATE_MIN;
4331c6a0718SPierre Ossman 	mmc->f_max = CLOCKRATE_MAX;
4341c6a0718SPierre Ossman 
4351c6a0718SPierre Ossman 	/*
4361c6a0718SPierre Ossman 	 * We can do SG-DMA, but we don't because we never know how much
4371c6a0718SPierre Ossman 	 * data we successfully wrote to the card.
4381c6a0718SPierre Ossman 	 */
4391c6a0718SPierre Ossman 	mmc->max_phys_segs = NR_SG;
4401c6a0718SPierre Ossman 
4411c6a0718SPierre Ossman 	/*
4421c6a0718SPierre Ossman 	 * Our hardware DMA can handle a maximum of one page per SG entry.
4431c6a0718SPierre Ossman 	 */
4441c6a0718SPierre Ossman 	mmc->max_seg_size = PAGE_SIZE;
4451c6a0718SPierre Ossman 
4461c6a0718SPierre Ossman 	/*
4471c6a0718SPierre Ossman 	 * Block length register is 10 bits.
4481c6a0718SPierre Ossman 	 */
4491c6a0718SPierre Ossman 	mmc->max_blk_size = 1023;
4501c6a0718SPierre Ossman 
4511c6a0718SPierre Ossman 	/*
4521c6a0718SPierre Ossman 	 * Block count register is 16 bits.
4531c6a0718SPierre Ossman 	 */
4541c6a0718SPierre Ossman 	mmc->max_blk_count = 65535;
4551c6a0718SPierre Ossman 
4561c6a0718SPierre Ossman 	host = mmc_priv(mmc);
4571c6a0718SPierre Ossman 	host->mmc = mmc;
4581c6a0718SPierre Ossman 	host->dma = -1;
4591c6a0718SPierre Ossman 	host->pdata = pdev->dev.platform_data;
4601c6a0718SPierre Ossman 	mmc->ocr_avail = host->pdata ?
4611c6a0718SPierre Ossman 			 host->pdata->ocr_mask :
4621c6a0718SPierre Ossman 			 MMC_VDD_32_33|MMC_VDD_33_34;
4631c6a0718SPierre Ossman 
4641c6a0718SPierre Ossman 	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
4651c6a0718SPierre Ossman 	if (!host->sg_cpu) {
4661c6a0718SPierre Ossman 		ret = -ENOMEM;
4671c6a0718SPierre Ossman 		goto out;
4681c6a0718SPierre Ossman 	}
4691c6a0718SPierre Ossman 
4701c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
4711c6a0718SPierre Ossman 	host->res = r;
4721c6a0718SPierre Ossman 	host->irq = irq;
4731c6a0718SPierre Ossman 	host->imask = MMC_I_MASK_ALL;
4741c6a0718SPierre Ossman 
4751c6a0718SPierre Ossman 	host->base = ioremap(r->start, SZ_4K);
4761c6a0718SPierre Ossman 	if (!host->base) {
4771c6a0718SPierre Ossman 		ret = -ENOMEM;
4781c6a0718SPierre Ossman 		goto out;
4791c6a0718SPierre Ossman 	}
4801c6a0718SPierre Ossman 
4811c6a0718SPierre Ossman 	/*
4821c6a0718SPierre Ossman 	 * Ensure that the host controller is shut down, and setup
4831c6a0718SPierre Ossman 	 * with our defaults.
4841c6a0718SPierre Ossman 	 */
4851c6a0718SPierre Ossman 	pxamci_stop_clock(host);
4861c6a0718SPierre Ossman 	writel(0, host->base + MMC_SPI);
4871c6a0718SPierre Ossman 	writel(64, host->base + MMC_RESTO);
4881c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
4891c6a0718SPierre Ossman 
4901c6a0718SPierre Ossman 	host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
4911c6a0718SPierre Ossman 				    pxamci_dma_irq, host);
4921c6a0718SPierre Ossman 	if (host->dma < 0) {
4931c6a0718SPierre Ossman 		ret = -EBUSY;
4941c6a0718SPierre Ossman 		goto out;
4951c6a0718SPierre Ossman 	}
4961c6a0718SPierre Ossman 
4971c6a0718SPierre Ossman 	ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
4981c6a0718SPierre Ossman 	if (ret)
4991c6a0718SPierre Ossman 		goto out;
5001c6a0718SPierre Ossman 
5011c6a0718SPierre Ossman 	platform_set_drvdata(pdev, mmc);
5021c6a0718SPierre Ossman 
5031c6a0718SPierre Ossman 	if (host->pdata && host->pdata->init)
5041c6a0718SPierre Ossman 		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
5051c6a0718SPierre Ossman 
5061c6a0718SPierre Ossman 	mmc_add_host(mmc);
5071c6a0718SPierre Ossman 
5081c6a0718SPierre Ossman 	return 0;
5091c6a0718SPierre Ossman 
5101c6a0718SPierre Ossman  out:
5111c6a0718SPierre Ossman 	if (host) {
5121c6a0718SPierre Ossman 		if (host->dma >= 0)
5131c6a0718SPierre Ossman 			pxa_free_dma(host->dma);
5141c6a0718SPierre Ossman 		if (host->base)
5151c6a0718SPierre Ossman 			iounmap(host->base);
5161c6a0718SPierre Ossman 		if (host->sg_cpu)
5171c6a0718SPierre Ossman 			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
5181c6a0718SPierre Ossman 	}
5191c6a0718SPierre Ossman 	if (mmc)
5201c6a0718SPierre Ossman 		mmc_free_host(mmc);
5211c6a0718SPierre Ossman 	release_resource(r);
5221c6a0718SPierre Ossman 	return ret;
5231c6a0718SPierre Ossman }
5241c6a0718SPierre Ossman 
5251c6a0718SPierre Ossman static int pxamci_remove(struct platform_device *pdev)
5261c6a0718SPierre Ossman {
5271c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(pdev);
5281c6a0718SPierre Ossman 
5291c6a0718SPierre Ossman 	platform_set_drvdata(pdev, NULL);
5301c6a0718SPierre Ossman 
5311c6a0718SPierre Ossman 	if (mmc) {
5321c6a0718SPierre Ossman 		struct pxamci_host *host = mmc_priv(mmc);
5331c6a0718SPierre Ossman 
5341c6a0718SPierre Ossman 		if (host->pdata && host->pdata->exit)
5351c6a0718SPierre Ossman 			host->pdata->exit(&pdev->dev, mmc);
5361c6a0718SPierre Ossman 
5371c6a0718SPierre Ossman 		mmc_remove_host(mmc);
5381c6a0718SPierre Ossman 
5391c6a0718SPierre Ossman 		pxamci_stop_clock(host);
5401c6a0718SPierre Ossman 		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
5411c6a0718SPierre Ossman 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
5421c6a0718SPierre Ossman 		       host->base + MMC_I_MASK);
5431c6a0718SPierre Ossman 
5441c6a0718SPierre Ossman 		DRCMRRXMMC = 0;
5451c6a0718SPierre Ossman 		DRCMRTXMMC = 0;
5461c6a0718SPierre Ossman 
5471c6a0718SPierre Ossman 		free_irq(host->irq, host);
5481c6a0718SPierre Ossman 		pxa_free_dma(host->dma);
5491c6a0718SPierre Ossman 		iounmap(host->base);
5501c6a0718SPierre Ossman 		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
5511c6a0718SPierre Ossman 
5521c6a0718SPierre Ossman 		release_resource(host->res);
5531c6a0718SPierre Ossman 
5541c6a0718SPierre Ossman 		mmc_free_host(mmc);
5551c6a0718SPierre Ossman 	}
5561c6a0718SPierre Ossman 	return 0;
5571c6a0718SPierre Ossman }
5581c6a0718SPierre Ossman 
5591c6a0718SPierre Ossman #ifdef CONFIG_PM
5601c6a0718SPierre Ossman static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
5611c6a0718SPierre Ossman {
5621c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(dev);
5631c6a0718SPierre Ossman 	int ret = 0;
5641c6a0718SPierre Ossman 
5651c6a0718SPierre Ossman 	if (mmc)
5661c6a0718SPierre Ossman 		ret = mmc_suspend_host(mmc, state);
5671c6a0718SPierre Ossman 
5681c6a0718SPierre Ossman 	return ret;
5691c6a0718SPierre Ossman }
5701c6a0718SPierre Ossman 
5711c6a0718SPierre Ossman static int pxamci_resume(struct platform_device *dev)
5721c6a0718SPierre Ossman {
5731c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(dev);
5741c6a0718SPierre Ossman 	int ret = 0;
5751c6a0718SPierre Ossman 
5761c6a0718SPierre Ossman 	if (mmc)
5771c6a0718SPierre Ossman 		ret = mmc_resume_host(mmc);
5781c6a0718SPierre Ossman 
5791c6a0718SPierre Ossman 	return ret;
5801c6a0718SPierre Ossman }
5811c6a0718SPierre Ossman #else
5821c6a0718SPierre Ossman #define pxamci_suspend	NULL
5831c6a0718SPierre Ossman #define pxamci_resume	NULL
5841c6a0718SPierre Ossman #endif
5851c6a0718SPierre Ossman 
5861c6a0718SPierre Ossman static struct platform_driver pxamci_driver = {
5871c6a0718SPierre Ossman 	.probe		= pxamci_probe,
5881c6a0718SPierre Ossman 	.remove		= pxamci_remove,
5891c6a0718SPierre Ossman 	.suspend	= pxamci_suspend,
5901c6a0718SPierre Ossman 	.resume		= pxamci_resume,
5911c6a0718SPierre Ossman 	.driver		= {
5921c6a0718SPierre Ossman 		.name	= DRIVER_NAME,
5931c6a0718SPierre Ossman 	},
5941c6a0718SPierre Ossman };
5951c6a0718SPierre Ossman 
5961c6a0718SPierre Ossman static int __init pxamci_init(void)
5971c6a0718SPierre Ossman {
5981c6a0718SPierre Ossman 	return platform_driver_register(&pxamci_driver);
5991c6a0718SPierre Ossman }
6001c6a0718SPierre Ossman 
6011c6a0718SPierre Ossman static void __exit pxamci_exit(void)
6021c6a0718SPierre Ossman {
6031c6a0718SPierre Ossman 	platform_driver_unregister(&pxamci_driver);
6041c6a0718SPierre Ossman }
6051c6a0718SPierre Ossman 
6061c6a0718SPierre Ossman module_init(pxamci_init);
6071c6a0718SPierre Ossman module_exit(pxamci_exit);
6081c6a0718SPierre Ossman 
6091c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
6101c6a0718SPierre Ossman MODULE_LICENSE("GPL");
611