xref: /openbmc/linux/drivers/mmc/host/mmci.c (revision 4b8caec0)
11c6a0718SPierre Ossman /*
270f10482SPierre Ossman  *  linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
31c6a0718SPierre Ossman  *
41c6a0718SPierre Ossman  *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
564de0289SLinus Walleij  *  Copyright (C) 2010 ST-Ericsson AB.
61c6a0718SPierre Ossman  *
71c6a0718SPierre Ossman  * This program is free software; you can redistribute it and/or modify
81c6a0718SPierre Ossman  * it under the terms of the GNU General Public License version 2 as
91c6a0718SPierre Ossman  * published by the Free Software Foundation.
101c6a0718SPierre Ossman  */
111c6a0718SPierre Ossman #include <linux/module.h>
121c6a0718SPierre Ossman #include <linux/moduleparam.h>
131c6a0718SPierre Ossman #include <linux/init.h>
141c6a0718SPierre Ossman #include <linux/ioport.h>
151c6a0718SPierre Ossman #include <linux/device.h>
161c6a0718SPierre Ossman #include <linux/interrupt.h>
171c6a0718SPierre Ossman #include <linux/delay.h>
181c6a0718SPierre Ossman #include <linux/err.h>
191c6a0718SPierre Ossman #include <linux/highmem.h>
20019a5f56SNicolas Pitre #include <linux/log2.h>
211c6a0718SPierre Ossman #include <linux/mmc/host.h>
221c6a0718SPierre Ossman #include <linux/amba/bus.h>
231c6a0718SPierre Ossman #include <linux/clk.h>
24bd6dee6fSJens Axboe #include <linux/scatterlist.h>
2589001446SRussell King #include <linux/gpio.h>
266ef297f8SLinus Walleij #include <linux/amba/mmci.h>
2734e84f39SLinus Walleij #include <linux/regulator/consumer.h>
281c6a0718SPierre Ossman 
291c6a0718SPierre Ossman #include <asm/div64.h>
301c6a0718SPierre Ossman #include <asm/io.h>
311c6a0718SPierre Ossman #include <asm/sizes.h>
321c6a0718SPierre Ossman 
331c6a0718SPierre Ossman #include "mmci.h"
341c6a0718SPierre Ossman 
351c6a0718SPierre Ossman #define DRIVER_NAME "mmci-pl18x"
361c6a0718SPierre Ossman 
371c6a0718SPierre Ossman static unsigned int fmax = 515633;
381c6a0718SPierre Ossman 
394956e109SRabin Vincent /**
404956e109SRabin Vincent  * struct variant_data - MMCI variant-specific quirks
414956e109SRabin Vincent  * @clkreg: default value for MCICLOCK register
424380c14fSRabin Vincent  * @clkreg_enable: enable value for MMCICLOCK register
4308458ef6SRabin Vincent  * @datalength_bits: number of bits in the MMCIDATALENGTH register
448301bb68SRabin Vincent  * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
458301bb68SRabin Vincent  *	      is asserted (likewise for RX)
468301bb68SRabin Vincent  * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
478301bb68SRabin Vincent  *		  is asserted (likewise for RX)
484956e109SRabin Vincent  */
494956e109SRabin Vincent struct variant_data {
504956e109SRabin Vincent 	unsigned int		clkreg;
514380c14fSRabin Vincent 	unsigned int		clkreg_enable;
5208458ef6SRabin Vincent 	unsigned int		datalength_bits;
538301bb68SRabin Vincent 	unsigned int		fifosize;
548301bb68SRabin Vincent 	unsigned int		fifohalfsize;
554956e109SRabin Vincent };
564956e109SRabin Vincent 
574956e109SRabin Vincent static struct variant_data variant_arm = {
588301bb68SRabin Vincent 	.fifosize		= 16 * 4,
598301bb68SRabin Vincent 	.fifohalfsize		= 8 * 4,
6008458ef6SRabin Vincent 	.datalength_bits	= 16,
614956e109SRabin Vincent };
624956e109SRabin Vincent 
634956e109SRabin Vincent static struct variant_data variant_u300 = {
648301bb68SRabin Vincent 	.fifosize		= 16 * 4,
658301bb68SRabin Vincent 	.fifohalfsize		= 8 * 4,
664380c14fSRabin Vincent 	.clkreg_enable		= 1 << 13, /* HWFCEN */
6708458ef6SRabin Vincent 	.datalength_bits	= 16,
684956e109SRabin Vincent };
694956e109SRabin Vincent 
704956e109SRabin Vincent static struct variant_data variant_ux500 = {
718301bb68SRabin Vincent 	.fifosize		= 30 * 4,
728301bb68SRabin Vincent 	.fifohalfsize		= 8 * 4,
734956e109SRabin Vincent 	.clkreg			= MCI_CLK_ENABLE,
744380c14fSRabin Vincent 	.clkreg_enable		= 1 << 14, /* HWFCEN */
7508458ef6SRabin Vincent 	.datalength_bits	= 24,
764956e109SRabin Vincent };
77a6a6464aSLinus Walleij /*
78a6a6464aSLinus Walleij  * This must be called with host->lock held
79a6a6464aSLinus Walleij  */
80a6a6464aSLinus Walleij static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
81a6a6464aSLinus Walleij {
824956e109SRabin Vincent 	struct variant_data *variant = host->variant;
834956e109SRabin Vincent 	u32 clk = variant->clkreg;
84a6a6464aSLinus Walleij 
85a6a6464aSLinus Walleij 	if (desired) {
86a6a6464aSLinus Walleij 		if (desired >= host->mclk) {
87a6a6464aSLinus Walleij 			clk = MCI_CLK_BYPASS;
88a6a6464aSLinus Walleij 			host->cclk = host->mclk;
89a6a6464aSLinus Walleij 		} else {
90a6a6464aSLinus Walleij 			clk = host->mclk / (2 * desired) - 1;
91a6a6464aSLinus Walleij 			if (clk >= 256)
92a6a6464aSLinus Walleij 				clk = 255;
93a6a6464aSLinus Walleij 			host->cclk = host->mclk / (2 * (clk + 1));
94a6a6464aSLinus Walleij 		}
954380c14fSRabin Vincent 
964380c14fSRabin Vincent 		clk |= variant->clkreg_enable;
97a6a6464aSLinus Walleij 		clk |= MCI_CLK_ENABLE;
98a6a6464aSLinus Walleij 		/* This hasn't proven to be worthwhile */
99a6a6464aSLinus Walleij 		/* clk |= MCI_CLK_PWRSAVE; */
100a6a6464aSLinus Walleij 	}
101a6a6464aSLinus Walleij 
1029e6c82cdSLinus Walleij 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
103771dc157SLinus Walleij 		clk |= MCI_4BIT_BUS;
104771dc157SLinus Walleij 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
105771dc157SLinus Walleij 		clk |= MCI_ST_8BIT_BUS;
1069e6c82cdSLinus Walleij 
107a6a6464aSLinus Walleij 	writel(clk, host->base + MMCICLOCK);
108a6a6464aSLinus Walleij }
109a6a6464aSLinus Walleij 
1101c6a0718SPierre Ossman static void
1111c6a0718SPierre Ossman mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
1121c6a0718SPierre Ossman {
1131c6a0718SPierre Ossman 	writel(0, host->base + MMCICOMMAND);
1141c6a0718SPierre Ossman 
1151c6a0718SPierre Ossman 	BUG_ON(host->data);
1161c6a0718SPierre Ossman 
1171c6a0718SPierre Ossman 	host->mrq = NULL;
1181c6a0718SPierre Ossman 	host->cmd = NULL;
1191c6a0718SPierre Ossman 
1201c6a0718SPierre Ossman 	if (mrq->data)
1211c6a0718SPierre Ossman 		mrq->data->bytes_xfered = host->data_xfered;
1221c6a0718SPierre Ossman 
1231c6a0718SPierre Ossman 	/*
1241c6a0718SPierre Ossman 	 * Need to drop the host lock here; mmc_request_done may call
1251c6a0718SPierre Ossman 	 * back into the driver...
1261c6a0718SPierre Ossman 	 */
1271c6a0718SPierre Ossman 	spin_unlock(&host->lock);
1281c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
1291c6a0718SPierre Ossman 	spin_lock(&host->lock);
1301c6a0718SPierre Ossman }
1311c6a0718SPierre Ossman 
1321c6a0718SPierre Ossman static void mmci_stop_data(struct mmci_host *host)
1331c6a0718SPierre Ossman {
1341c6a0718SPierre Ossman 	writel(0, host->base + MMCIDATACTRL);
1351c6a0718SPierre Ossman 	writel(0, host->base + MMCIMASK1);
1361c6a0718SPierre Ossman 	host->data = NULL;
1371c6a0718SPierre Ossman }
1381c6a0718SPierre Ossman 
1394ce1d6cbSRabin Vincent static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
1404ce1d6cbSRabin Vincent {
1414ce1d6cbSRabin Vincent 	unsigned int flags = SG_MITER_ATOMIC;
1424ce1d6cbSRabin Vincent 
1434ce1d6cbSRabin Vincent 	if (data->flags & MMC_DATA_READ)
1444ce1d6cbSRabin Vincent 		flags |= SG_MITER_TO_SG;
1454ce1d6cbSRabin Vincent 	else
1464ce1d6cbSRabin Vincent 		flags |= SG_MITER_FROM_SG;
1474ce1d6cbSRabin Vincent 
1484ce1d6cbSRabin Vincent 	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
1494ce1d6cbSRabin Vincent }
1504ce1d6cbSRabin Vincent 
1511c6a0718SPierre Ossman static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
1521c6a0718SPierre Ossman {
1538301bb68SRabin Vincent 	struct variant_data *variant = host->variant;
1541c6a0718SPierre Ossman 	unsigned int datactrl, timeout, irqmask;
1551c6a0718SPierre Ossman 	unsigned long long clks;
1561c6a0718SPierre Ossman 	void __iomem *base;
1571c6a0718SPierre Ossman 	int blksz_bits;
1581c6a0718SPierre Ossman 
15964de0289SLinus Walleij 	dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
1601c6a0718SPierre Ossman 		data->blksz, data->blocks, data->flags);
1611c6a0718SPierre Ossman 
1621c6a0718SPierre Ossman 	host->data = data;
163528320dbSRabin Vincent 	host->size = data->blksz * data->blocks;
1641c6a0718SPierre Ossman 	host->data_xfered = 0;
1651c6a0718SPierre Ossman 
1661c6a0718SPierre Ossman 	mmci_init_sg(host, data);
1671c6a0718SPierre Ossman 
1681c6a0718SPierre Ossman 	clks = (unsigned long long)data->timeout_ns * host->cclk;
1691c6a0718SPierre Ossman 	do_div(clks, 1000000000UL);
1701c6a0718SPierre Ossman 
1711c6a0718SPierre Ossman 	timeout = data->timeout_clks + (unsigned int)clks;
1721c6a0718SPierre Ossman 
1731c6a0718SPierre Ossman 	base = host->base;
1741c6a0718SPierre Ossman 	writel(timeout, base + MMCIDATATIMER);
1751c6a0718SPierre Ossman 	writel(host->size, base + MMCIDATALENGTH);
1761c6a0718SPierre Ossman 
1771c6a0718SPierre Ossman 	blksz_bits = ffs(data->blksz) - 1;
1781c6a0718SPierre Ossman 	BUG_ON(1 << blksz_bits != data->blksz);
1791c6a0718SPierre Ossman 
1801c6a0718SPierre Ossman 	datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
1811c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ) {
1821c6a0718SPierre Ossman 		datactrl |= MCI_DPSM_DIRECTION;
1831c6a0718SPierre Ossman 		irqmask = MCI_RXFIFOHALFFULLMASK;
1841c6a0718SPierre Ossman 
1851c6a0718SPierre Ossman 		/*
1861c6a0718SPierre Ossman 		 * If we have less than a FIFOSIZE of bytes to transfer,
1871c6a0718SPierre Ossman 		 * trigger a PIO interrupt as soon as any data is available.
1881c6a0718SPierre Ossman 		 */
1898301bb68SRabin Vincent 		if (host->size < variant->fifosize)
1901c6a0718SPierre Ossman 			irqmask |= MCI_RXDATAAVLBLMASK;
1911c6a0718SPierre Ossman 	} else {
1921c6a0718SPierre Ossman 		/*
1931c6a0718SPierre Ossman 		 * We don't actually need to include "FIFO empty" here
1941c6a0718SPierre Ossman 		 * since its implicit in "FIFO half empty".
1951c6a0718SPierre Ossman 		 */
1961c6a0718SPierre Ossman 		irqmask = MCI_TXFIFOHALFEMPTYMASK;
1971c6a0718SPierre Ossman 	}
1981c6a0718SPierre Ossman 
1991c6a0718SPierre Ossman 	writel(datactrl, base + MMCIDATACTRL);
2001c6a0718SPierre Ossman 	writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
2011c6a0718SPierre Ossman 	writel(irqmask, base + MMCIMASK1);
2021c6a0718SPierre Ossman }
2031c6a0718SPierre Ossman 
2041c6a0718SPierre Ossman static void
2051c6a0718SPierre Ossman mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
2061c6a0718SPierre Ossman {
2071c6a0718SPierre Ossman 	void __iomem *base = host->base;
2081c6a0718SPierre Ossman 
20964de0289SLinus Walleij 	dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
2101c6a0718SPierre Ossman 	    cmd->opcode, cmd->arg, cmd->flags);
2111c6a0718SPierre Ossman 
2121c6a0718SPierre Ossman 	if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
2131c6a0718SPierre Ossman 		writel(0, base + MMCICOMMAND);
2141c6a0718SPierre Ossman 		udelay(1);
2151c6a0718SPierre Ossman 	}
2161c6a0718SPierre Ossman 
2171c6a0718SPierre Ossman 	c |= cmd->opcode | MCI_CPSM_ENABLE;
2181c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_PRESENT) {
2191c6a0718SPierre Ossman 		if (cmd->flags & MMC_RSP_136)
2201c6a0718SPierre Ossman 			c |= MCI_CPSM_LONGRSP;
2211c6a0718SPierre Ossman 		c |= MCI_CPSM_RESPONSE;
2221c6a0718SPierre Ossman 	}
2231c6a0718SPierre Ossman 	if (/*interrupt*/0)
2241c6a0718SPierre Ossman 		c |= MCI_CPSM_INTERRUPT;
2251c6a0718SPierre Ossman 
2261c6a0718SPierre Ossman 	host->cmd = cmd;
2271c6a0718SPierre Ossman 
2281c6a0718SPierre Ossman 	writel(cmd->arg, base + MMCIARGUMENT);
2291c6a0718SPierre Ossman 	writel(c, base + MMCICOMMAND);
2301c6a0718SPierre Ossman }
2311c6a0718SPierre Ossman 
2321c6a0718SPierre Ossman static void
2331c6a0718SPierre Ossman mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
2341c6a0718SPierre Ossman 	      unsigned int status)
2351c6a0718SPierre Ossman {
2361c6a0718SPierre Ossman 	if (status & MCI_DATABLOCKEND) {
2371c6a0718SPierre Ossman 		host->data_xfered += data->blksz;
238f28e8a4dSLinus Walleij #ifdef CONFIG_ARCH_U300
239f28e8a4dSLinus Walleij 		/*
240f28e8a4dSLinus Walleij 		 * On the U300 some signal or other is
241f28e8a4dSLinus Walleij 		 * badly routed so that a data write does
242f28e8a4dSLinus Walleij 		 * not properly terminate with a MCI_DATAEND
243f28e8a4dSLinus Walleij 		 * status flag. This quirk will make writes
244f28e8a4dSLinus Walleij 		 * work again.
245f28e8a4dSLinus Walleij 		 */
246f28e8a4dSLinus Walleij 		if (data->flags & MMC_DATA_WRITE)
247f28e8a4dSLinus Walleij 			status |= MCI_DATAEND;
248f28e8a4dSLinus Walleij #endif
2491c6a0718SPierre Ossman 	}
2501c6a0718SPierre Ossman 	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
25164de0289SLinus Walleij 		dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
2521c6a0718SPierre Ossman 		if (status & MCI_DATACRCFAIL)
25317b0429dSPierre Ossman 			data->error = -EILSEQ;
2541c6a0718SPierre Ossman 		else if (status & MCI_DATATIMEOUT)
25517b0429dSPierre Ossman 			data->error = -ETIMEDOUT;
2561c6a0718SPierre Ossman 		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
25717b0429dSPierre Ossman 			data->error = -EIO;
2581c6a0718SPierre Ossman 		status |= MCI_DATAEND;
2591c6a0718SPierre Ossman 
2601c6a0718SPierre Ossman 		/*
2611c6a0718SPierre Ossman 		 * We hit an error condition.  Ensure that any data
2621c6a0718SPierre Ossman 		 * partially written to a page is properly coherent.
2631c6a0718SPierre Ossman 		 */
2644ce1d6cbSRabin Vincent 		if (data->flags & MMC_DATA_READ) {
2654ce1d6cbSRabin Vincent 			struct sg_mapping_iter *sg_miter = &host->sg_miter;
2664ce1d6cbSRabin Vincent 			unsigned long flags;
2674ce1d6cbSRabin Vincent 
2684ce1d6cbSRabin Vincent 			local_irq_save(flags);
2694ce1d6cbSRabin Vincent 			if (sg_miter_next(sg_miter)) {
2704ce1d6cbSRabin Vincent 				flush_dcache_page(sg_miter->page);
2714ce1d6cbSRabin Vincent 				sg_miter_stop(sg_miter);
2724ce1d6cbSRabin Vincent 			}
2734ce1d6cbSRabin Vincent 			local_irq_restore(flags);
2744ce1d6cbSRabin Vincent 		}
2751c6a0718SPierre Ossman 	}
2761c6a0718SPierre Ossman 	if (status & MCI_DATAEND) {
2771c6a0718SPierre Ossman 		mmci_stop_data(host);
2781c6a0718SPierre Ossman 
2791c6a0718SPierre Ossman 		if (!data->stop) {
2801c6a0718SPierre Ossman 			mmci_request_end(host, data->mrq);
2811c6a0718SPierre Ossman 		} else {
2821c6a0718SPierre Ossman 			mmci_start_command(host, data->stop, 0);
2831c6a0718SPierre Ossman 		}
2841c6a0718SPierre Ossman 	}
2851c6a0718SPierre Ossman }
2861c6a0718SPierre Ossman 
2871c6a0718SPierre Ossman static void
2881c6a0718SPierre Ossman mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
2891c6a0718SPierre Ossman 	     unsigned int status)
2901c6a0718SPierre Ossman {
2911c6a0718SPierre Ossman 	void __iomem *base = host->base;
2921c6a0718SPierre Ossman 
2931c6a0718SPierre Ossman 	host->cmd = NULL;
2941c6a0718SPierre Ossman 
2951c6a0718SPierre Ossman 	cmd->resp[0] = readl(base + MMCIRESPONSE0);
2961c6a0718SPierre Ossman 	cmd->resp[1] = readl(base + MMCIRESPONSE1);
2971c6a0718SPierre Ossman 	cmd->resp[2] = readl(base + MMCIRESPONSE2);
2981c6a0718SPierre Ossman 	cmd->resp[3] = readl(base + MMCIRESPONSE3);
2991c6a0718SPierre Ossman 
3001c6a0718SPierre Ossman 	if (status & MCI_CMDTIMEOUT) {
30117b0429dSPierre Ossman 		cmd->error = -ETIMEDOUT;
3021c6a0718SPierre Ossman 	} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
30317b0429dSPierre Ossman 		cmd->error = -EILSEQ;
3041c6a0718SPierre Ossman 	}
3051c6a0718SPierre Ossman 
30617b0429dSPierre Ossman 	if (!cmd->data || cmd->error) {
3071c6a0718SPierre Ossman 		if (host->data)
3081c6a0718SPierre Ossman 			mmci_stop_data(host);
3091c6a0718SPierre Ossman 		mmci_request_end(host, cmd->mrq);
3101c6a0718SPierre Ossman 	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
3111c6a0718SPierre Ossman 		mmci_start_data(host, cmd->data);
3121c6a0718SPierre Ossman 	}
3131c6a0718SPierre Ossman }
3141c6a0718SPierre Ossman 
3151c6a0718SPierre Ossman static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
3161c6a0718SPierre Ossman {
3171c6a0718SPierre Ossman 	void __iomem *base = host->base;
3181c6a0718SPierre Ossman 	char *ptr = buffer;
3191c6a0718SPierre Ossman 	u32 status;
32026eed9a5SLinus Walleij 	int host_remain = host->size;
3211c6a0718SPierre Ossman 
3221c6a0718SPierre Ossman 	do {
32326eed9a5SLinus Walleij 		int count = host_remain - (readl(base + MMCIFIFOCNT) << 2);
3241c6a0718SPierre Ossman 
3251c6a0718SPierre Ossman 		if (count > remain)
3261c6a0718SPierre Ossman 			count = remain;
3271c6a0718SPierre Ossman 
3281c6a0718SPierre Ossman 		if (count <= 0)
3291c6a0718SPierre Ossman 			break;
3301c6a0718SPierre Ossman 
3311c6a0718SPierre Ossman 		readsl(base + MMCIFIFO, ptr, count >> 2);
3321c6a0718SPierre Ossman 
3331c6a0718SPierre Ossman 		ptr += count;
3341c6a0718SPierre Ossman 		remain -= count;
33526eed9a5SLinus Walleij 		host_remain -= count;
3361c6a0718SPierre Ossman 
3371c6a0718SPierre Ossman 		if (remain == 0)
3381c6a0718SPierre Ossman 			break;
3391c6a0718SPierre Ossman 
3401c6a0718SPierre Ossman 		status = readl(base + MMCISTATUS);
3411c6a0718SPierre Ossman 	} while (status & MCI_RXDATAAVLBL);
3421c6a0718SPierre Ossman 
3431c6a0718SPierre Ossman 	return ptr - buffer;
3441c6a0718SPierre Ossman }
3451c6a0718SPierre Ossman 
3461c6a0718SPierre Ossman static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
3471c6a0718SPierre Ossman {
3488301bb68SRabin Vincent 	struct variant_data *variant = host->variant;
3491c6a0718SPierre Ossman 	void __iomem *base = host->base;
3501c6a0718SPierre Ossman 	char *ptr = buffer;
3511c6a0718SPierre Ossman 
3521c6a0718SPierre Ossman 	do {
3531c6a0718SPierre Ossman 		unsigned int count, maxcnt;
3541c6a0718SPierre Ossman 
3558301bb68SRabin Vincent 		maxcnt = status & MCI_TXFIFOEMPTY ?
3568301bb68SRabin Vincent 			 variant->fifosize : variant->fifohalfsize;
3571c6a0718SPierre Ossman 		count = min(remain, maxcnt);
3581c6a0718SPierre Ossman 
3591c6a0718SPierre Ossman 		writesl(base + MMCIFIFO, ptr, count >> 2);
3601c6a0718SPierre Ossman 
3611c6a0718SPierre Ossman 		ptr += count;
3621c6a0718SPierre Ossman 		remain -= count;
3631c6a0718SPierre Ossman 
3641c6a0718SPierre Ossman 		if (remain == 0)
3651c6a0718SPierre Ossman 			break;
3661c6a0718SPierre Ossman 
3671c6a0718SPierre Ossman 		status = readl(base + MMCISTATUS);
3681c6a0718SPierre Ossman 	} while (status & MCI_TXFIFOHALFEMPTY);
3691c6a0718SPierre Ossman 
3701c6a0718SPierre Ossman 	return ptr - buffer;
3711c6a0718SPierre Ossman }
3721c6a0718SPierre Ossman 
3731c6a0718SPierre Ossman /*
3741c6a0718SPierre Ossman  * PIO data transfer IRQ handler.
3751c6a0718SPierre Ossman  */
3761c6a0718SPierre Ossman static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
3771c6a0718SPierre Ossman {
3781c6a0718SPierre Ossman 	struct mmci_host *host = dev_id;
3794ce1d6cbSRabin Vincent 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
3808301bb68SRabin Vincent 	struct variant_data *variant = host->variant;
3811c6a0718SPierre Ossman 	void __iomem *base = host->base;
3824ce1d6cbSRabin Vincent 	unsigned long flags;
3831c6a0718SPierre Ossman 	u32 status;
3841c6a0718SPierre Ossman 
3851c6a0718SPierre Ossman 	status = readl(base + MMCISTATUS);
3861c6a0718SPierre Ossman 
38764de0289SLinus Walleij 	dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
3881c6a0718SPierre Ossman 
3894ce1d6cbSRabin Vincent 	local_irq_save(flags);
3904ce1d6cbSRabin Vincent 
3911c6a0718SPierre Ossman 	do {
3921c6a0718SPierre Ossman 		unsigned int remain, len;
3931c6a0718SPierre Ossman 		char *buffer;
3941c6a0718SPierre Ossman 
3951c6a0718SPierre Ossman 		/*
3961c6a0718SPierre Ossman 		 * For write, we only need to test the half-empty flag
3971c6a0718SPierre Ossman 		 * here - if the FIFO is completely empty, then by
3981c6a0718SPierre Ossman 		 * definition it is more than half empty.
3991c6a0718SPierre Ossman 		 *
4001c6a0718SPierre Ossman 		 * For read, check for data available.
4011c6a0718SPierre Ossman 		 */
4021c6a0718SPierre Ossman 		if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
4031c6a0718SPierre Ossman 			break;
4041c6a0718SPierre Ossman 
4054ce1d6cbSRabin Vincent 		if (!sg_miter_next(sg_miter))
4064ce1d6cbSRabin Vincent 			break;
4074ce1d6cbSRabin Vincent 
4084ce1d6cbSRabin Vincent 		buffer = sg_miter->addr;
4094ce1d6cbSRabin Vincent 		remain = sg_miter->length;
4101c6a0718SPierre Ossman 
4111c6a0718SPierre Ossman 		len = 0;
4121c6a0718SPierre Ossman 		if (status & MCI_RXACTIVE)
4131c6a0718SPierre Ossman 			len = mmci_pio_read(host, buffer, remain);
4141c6a0718SPierre Ossman 		if (status & MCI_TXACTIVE)
4151c6a0718SPierre Ossman 			len = mmci_pio_write(host, buffer, remain, status);
4161c6a0718SPierre Ossman 
4174ce1d6cbSRabin Vincent 		sg_miter->consumed = len;
4181c6a0718SPierre Ossman 
4191c6a0718SPierre Ossman 		host->size -= len;
4201c6a0718SPierre Ossman 		remain -= len;
4211c6a0718SPierre Ossman 
4221c6a0718SPierre Ossman 		if (remain)
4231c6a0718SPierre Ossman 			break;
4241c6a0718SPierre Ossman 
4251c6a0718SPierre Ossman 		if (status & MCI_RXACTIVE)
4264ce1d6cbSRabin Vincent 			flush_dcache_page(sg_miter->page);
4271c6a0718SPierre Ossman 
4281c6a0718SPierre Ossman 		status = readl(base + MMCISTATUS);
4291c6a0718SPierre Ossman 	} while (1);
4301c6a0718SPierre Ossman 
4314ce1d6cbSRabin Vincent 	sg_miter_stop(sg_miter);
4324ce1d6cbSRabin Vincent 
4334ce1d6cbSRabin Vincent 	local_irq_restore(flags);
4344ce1d6cbSRabin Vincent 
4351c6a0718SPierre Ossman 	/*
4361c6a0718SPierre Ossman 	 * If we're nearing the end of the read, switch to
4371c6a0718SPierre Ossman 	 * "any data available" mode.
4381c6a0718SPierre Ossman 	 */
4398301bb68SRabin Vincent 	if (status & MCI_RXACTIVE && host->size < variant->fifosize)
4401c6a0718SPierre Ossman 		writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
4411c6a0718SPierre Ossman 
4421c6a0718SPierre Ossman 	/*
4431c6a0718SPierre Ossman 	 * If we run out of data, disable the data IRQs; this
4441c6a0718SPierre Ossman 	 * prevents a race where the FIFO becomes empty before
4451c6a0718SPierre Ossman 	 * the chip itself has disabled the data path, and
4461c6a0718SPierre Ossman 	 * stops us racing with our data end IRQ.
4471c6a0718SPierre Ossman 	 */
4481c6a0718SPierre Ossman 	if (host->size == 0) {
4491c6a0718SPierre Ossman 		writel(0, base + MMCIMASK1);
4501c6a0718SPierre Ossman 		writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
4511c6a0718SPierre Ossman 	}
4521c6a0718SPierre Ossman 
4531c6a0718SPierre Ossman 	return IRQ_HANDLED;
4541c6a0718SPierre Ossman }
4551c6a0718SPierre Ossman 
4561c6a0718SPierre Ossman /*
4571c6a0718SPierre Ossman  * Handle completion of command and data transfers.
4581c6a0718SPierre Ossman  */
4591c6a0718SPierre Ossman static irqreturn_t mmci_irq(int irq, void *dev_id)
4601c6a0718SPierre Ossman {
4611c6a0718SPierre Ossman 	struct mmci_host *host = dev_id;
4621c6a0718SPierre Ossman 	u32 status;
4631c6a0718SPierre Ossman 	int ret = 0;
4641c6a0718SPierre Ossman 
4651c6a0718SPierre Ossman 	spin_lock(&host->lock);
4661c6a0718SPierre Ossman 
4671c6a0718SPierre Ossman 	do {
4681c6a0718SPierre Ossman 		struct mmc_command *cmd;
4691c6a0718SPierre Ossman 		struct mmc_data *data;
4701c6a0718SPierre Ossman 
4711c6a0718SPierre Ossman 		status = readl(host->base + MMCISTATUS);
4721c6a0718SPierre Ossman 		status &= readl(host->base + MMCIMASK0);
4731c6a0718SPierre Ossman 		writel(status, host->base + MMCICLEAR);
4741c6a0718SPierre Ossman 
47564de0289SLinus Walleij 		dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
4761c6a0718SPierre Ossman 
4771c6a0718SPierre Ossman 		data = host->data;
4781c6a0718SPierre Ossman 		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
4791c6a0718SPierre Ossman 			      MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
4801c6a0718SPierre Ossman 			mmci_data_irq(host, data, status);
4811c6a0718SPierre Ossman 
4821c6a0718SPierre Ossman 		cmd = host->cmd;
4831c6a0718SPierre Ossman 		if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
4841c6a0718SPierre Ossman 			mmci_cmd_irq(host, cmd, status);
4851c6a0718SPierre Ossman 
4861c6a0718SPierre Ossman 		ret = 1;
4871c6a0718SPierre Ossman 	} while (status);
4881c6a0718SPierre Ossman 
4891c6a0718SPierre Ossman 	spin_unlock(&host->lock);
4901c6a0718SPierre Ossman 
4911c6a0718SPierre Ossman 	return IRQ_RETVAL(ret);
4921c6a0718SPierre Ossman }
4931c6a0718SPierre Ossman 
4941c6a0718SPierre Ossman static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
4951c6a0718SPierre Ossman {
4961c6a0718SPierre Ossman 	struct mmci_host *host = mmc_priv(mmc);
4979e943021SLinus Walleij 	unsigned long flags;
4981c6a0718SPierre Ossman 
4991c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
5001c6a0718SPierre Ossman 
501019a5f56SNicolas Pitre 	if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
50264de0289SLinus Walleij 		dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
50364de0289SLinus Walleij 			mrq->data->blksz);
504255d01afSPierre Ossman 		mrq->cmd->error = -EINVAL;
505255d01afSPierre Ossman 		mmc_request_done(mmc, mrq);
506255d01afSPierre Ossman 		return;
507255d01afSPierre Ossman 	}
508255d01afSPierre Ossman 
5099e943021SLinus Walleij 	spin_lock_irqsave(&host->lock, flags);
5101c6a0718SPierre Ossman 
5111c6a0718SPierre Ossman 	host->mrq = mrq;
5121c6a0718SPierre Ossman 
5131c6a0718SPierre Ossman 	if (mrq->data && mrq->data->flags & MMC_DATA_READ)
5141c6a0718SPierre Ossman 		mmci_start_data(host, mrq->data);
5151c6a0718SPierre Ossman 
5161c6a0718SPierre Ossman 	mmci_start_command(host, mrq->cmd, 0);
5171c6a0718SPierre Ossman 
5189e943021SLinus Walleij 	spin_unlock_irqrestore(&host->lock, flags);
5191c6a0718SPierre Ossman }
5201c6a0718SPierre Ossman 
5211c6a0718SPierre Ossman static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
5221c6a0718SPierre Ossman {
5231c6a0718SPierre Ossman 	struct mmci_host *host = mmc_priv(mmc);
524a6a6464aSLinus Walleij 	u32 pwr = 0;
525a6a6464aSLinus Walleij 	unsigned long flags;
5261c6a0718SPierre Ossman 
5271c6a0718SPierre Ossman 	switch (ios->power_mode) {
5281c6a0718SPierre Ossman 	case MMC_POWER_OFF:
52934e84f39SLinus Walleij 		if(host->vcc &&
53034e84f39SLinus Walleij 		   regulator_is_enabled(host->vcc))
53134e84f39SLinus Walleij 			regulator_disable(host->vcc);
5321c6a0718SPierre Ossman 		break;
5331c6a0718SPierre Ossman 	case MMC_POWER_UP:
53434e84f39SLinus Walleij #ifdef CONFIG_REGULATOR
53534e84f39SLinus Walleij 		if (host->vcc)
53634e84f39SLinus Walleij 			/* This implicitly enables the regulator */
53734e84f39SLinus Walleij 			mmc_regulator_set_ocr(host->vcc, ios->vdd);
53834e84f39SLinus Walleij #endif
539bb8f563cSRabin Vincent 		if (host->plat->vdd_handler)
540bb8f563cSRabin Vincent 			pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
541bb8f563cSRabin Vincent 						       ios->power_mode);
542cc30d60eSLinus Walleij 		/* The ST version does not have this, fall through to POWER_ON */
543f17a1f06SLinus Walleij 		if (host->hw_designer != AMBA_VENDOR_ST) {
5441c6a0718SPierre Ossman 			pwr |= MCI_PWR_UP;
5451c6a0718SPierre Ossman 			break;
546cc30d60eSLinus Walleij 		}
5471c6a0718SPierre Ossman 	case MMC_POWER_ON:
5481c6a0718SPierre Ossman 		pwr |= MCI_PWR_ON;
5491c6a0718SPierre Ossman 		break;
5501c6a0718SPierre Ossman 	}
5511c6a0718SPierre Ossman 
552cc30d60eSLinus Walleij 	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
553f17a1f06SLinus Walleij 		if (host->hw_designer != AMBA_VENDOR_ST)
5541c6a0718SPierre Ossman 			pwr |= MCI_ROD;
555cc30d60eSLinus Walleij 		else {
556cc30d60eSLinus Walleij 			/*
557cc30d60eSLinus Walleij 			 * The ST Micro variant use the ROD bit for something
558cc30d60eSLinus Walleij 			 * else and only has OD (Open Drain).
559cc30d60eSLinus Walleij 			 */
560cc30d60eSLinus Walleij 			pwr |= MCI_OD;
561cc30d60eSLinus Walleij 		}
562cc30d60eSLinus Walleij 	}
5631c6a0718SPierre Ossman 
564a6a6464aSLinus Walleij 	spin_lock_irqsave(&host->lock, flags);
565a6a6464aSLinus Walleij 
566a6a6464aSLinus Walleij 	mmci_set_clkreg(host, ios->clock);
5671c6a0718SPierre Ossman 
5681c6a0718SPierre Ossman 	if (host->pwr != pwr) {
5691c6a0718SPierre Ossman 		host->pwr = pwr;
5701c6a0718SPierre Ossman 		writel(pwr, host->base + MMCIPOWER);
5711c6a0718SPierre Ossman 	}
572a6a6464aSLinus Walleij 
573a6a6464aSLinus Walleij 	spin_unlock_irqrestore(&host->lock, flags);
5741c6a0718SPierre Ossman }
5751c6a0718SPierre Ossman 
57689001446SRussell King static int mmci_get_ro(struct mmc_host *mmc)
57789001446SRussell King {
57889001446SRussell King 	struct mmci_host *host = mmc_priv(mmc);
57989001446SRussell King 
58089001446SRussell King 	if (host->gpio_wp == -ENOSYS)
58189001446SRussell King 		return -ENOSYS;
58289001446SRussell King 
58389001446SRussell King 	return gpio_get_value(host->gpio_wp);
58489001446SRussell King }
58589001446SRussell King 
58689001446SRussell King static int mmci_get_cd(struct mmc_host *mmc)
58789001446SRussell King {
58889001446SRussell King 	struct mmci_host *host = mmc_priv(mmc);
58929719445SRabin Vincent 	struct mmci_platform_data *plat = host->plat;
59089001446SRussell King 	unsigned int status;
59189001446SRussell King 
5924b8caec0SRabin Vincent 	if (host->gpio_cd == -ENOSYS) {
5934b8caec0SRabin Vincent 		if (!plat->status)
5944b8caec0SRabin Vincent 			return 1; /* Assume always present */
5954b8caec0SRabin Vincent 
59629719445SRabin Vincent 		status = plat->status(mmc_dev(host->mmc));
5974b8caec0SRabin Vincent 	} else
59829719445SRabin Vincent 		status = !!gpio_get_value(host->gpio_cd) ^ plat->cd_invert;
59989001446SRussell King 
60074bc8093SRussell King 	/*
60174bc8093SRussell King 	 * Use positive logic throughout - status is zero for no card,
60274bc8093SRussell King 	 * non-zero for card inserted.
60374bc8093SRussell King 	 */
60474bc8093SRussell King 	return status;
60589001446SRussell King }
60689001446SRussell King 
607148b8b39SRabin Vincent static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
608148b8b39SRabin Vincent {
609148b8b39SRabin Vincent 	struct mmci_host *host = dev_id;
610148b8b39SRabin Vincent 
611148b8b39SRabin Vincent 	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
612148b8b39SRabin Vincent 
613148b8b39SRabin Vincent 	return IRQ_HANDLED;
614148b8b39SRabin Vincent }
615148b8b39SRabin Vincent 
6161c6a0718SPierre Ossman static const struct mmc_host_ops mmci_ops = {
6171c6a0718SPierre Ossman 	.request	= mmci_request,
6181c6a0718SPierre Ossman 	.set_ios	= mmci_set_ios,
61989001446SRussell King 	.get_ro		= mmci_get_ro,
62089001446SRussell King 	.get_cd		= mmci_get_cd,
6211c6a0718SPierre Ossman };
6221c6a0718SPierre Ossman 
62303fbdb15SAlessandro Rubini static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
6241c6a0718SPierre Ossman {
6256ef297f8SLinus Walleij 	struct mmci_platform_data *plat = dev->dev.platform_data;
6264956e109SRabin Vincent 	struct variant_data *variant = id->data;
6271c6a0718SPierre Ossman 	struct mmci_host *host;
6281c6a0718SPierre Ossman 	struct mmc_host *mmc;
6291c6a0718SPierre Ossman 	int ret;
6301c6a0718SPierre Ossman 
6311c6a0718SPierre Ossman 	/* must have platform data */
6321c6a0718SPierre Ossman 	if (!plat) {
6331c6a0718SPierre Ossman 		ret = -EINVAL;
6341c6a0718SPierre Ossman 		goto out;
6351c6a0718SPierre Ossman 	}
6361c6a0718SPierre Ossman 
6371c6a0718SPierre Ossman 	ret = amba_request_regions(dev, DRIVER_NAME);
6381c6a0718SPierre Ossman 	if (ret)
6391c6a0718SPierre Ossman 		goto out;
6401c6a0718SPierre Ossman 
6411c6a0718SPierre Ossman 	mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
6421c6a0718SPierre Ossman 	if (!mmc) {
6431c6a0718SPierre Ossman 		ret = -ENOMEM;
6441c6a0718SPierre Ossman 		goto rel_regions;
6451c6a0718SPierre Ossman 	}
6461c6a0718SPierre Ossman 
6471c6a0718SPierre Ossman 	host = mmc_priv(mmc);
6484ea580f1SRabin Vincent 	host->mmc = mmc;
649012b7d33SRussell King 
65089001446SRussell King 	host->gpio_wp = -ENOSYS;
65189001446SRussell King 	host->gpio_cd = -ENOSYS;
652148b8b39SRabin Vincent 	host->gpio_cd_irq = -1;
65389001446SRussell King 
654012b7d33SRussell King 	host->hw_designer = amba_manf(dev);
655012b7d33SRussell King 	host->hw_revision = amba_rev(dev);
65664de0289SLinus Walleij 	dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
65764de0289SLinus Walleij 	dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
658012b7d33SRussell King 
659ee569c43SRussell King 	host->clk = clk_get(&dev->dev, NULL);
6601c6a0718SPierre Ossman 	if (IS_ERR(host->clk)) {
6611c6a0718SPierre Ossman 		ret = PTR_ERR(host->clk);
6621c6a0718SPierre Ossman 		host->clk = NULL;
6631c6a0718SPierre Ossman 		goto host_free;
6641c6a0718SPierre Ossman 	}
6651c6a0718SPierre Ossman 
6661c6a0718SPierre Ossman 	ret = clk_enable(host->clk);
6671c6a0718SPierre Ossman 	if (ret)
6681c6a0718SPierre Ossman 		goto clk_free;
6691c6a0718SPierre Ossman 
6701c6a0718SPierre Ossman 	host->plat = plat;
6714956e109SRabin Vincent 	host->variant = variant;
6721c6a0718SPierre Ossman 	host->mclk = clk_get_rate(host->clk);
673c8df9a53SLinus Walleij 	/*
674c8df9a53SLinus Walleij 	 * According to the spec, mclk is max 100 MHz,
675c8df9a53SLinus Walleij 	 * so we try to adjust the clock down to this,
676c8df9a53SLinus Walleij 	 * (if possible).
677c8df9a53SLinus Walleij 	 */
678c8df9a53SLinus Walleij 	if (host->mclk > 100000000) {
679c8df9a53SLinus Walleij 		ret = clk_set_rate(host->clk, 100000000);
680c8df9a53SLinus Walleij 		if (ret < 0)
681c8df9a53SLinus Walleij 			goto clk_disable;
682c8df9a53SLinus Walleij 		host->mclk = clk_get_rate(host->clk);
68364de0289SLinus Walleij 		dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
68464de0289SLinus Walleij 			host->mclk);
685c8df9a53SLinus Walleij 	}
686dc890c2dSLinus Walleij 	host->base = ioremap(dev->res.start, resource_size(&dev->res));
6871c6a0718SPierre Ossman 	if (!host->base) {
6881c6a0718SPierre Ossman 		ret = -ENOMEM;
6891c6a0718SPierre Ossman 		goto clk_disable;
6901c6a0718SPierre Ossman 	}
6911c6a0718SPierre Ossman 
6921c6a0718SPierre Ossman 	mmc->ops = &mmci_ops;
6931c6a0718SPierre Ossman 	mmc->f_min = (host->mclk + 511) / 512;
694808d97ccSLinus Walleij 	/*
695808d97ccSLinus Walleij 	 * If the platform data supplies a maximum operating
696808d97ccSLinus Walleij 	 * frequency, this takes precedence. Else, we fall back
697808d97ccSLinus Walleij 	 * to using the module parameter, which has a (low)
698808d97ccSLinus Walleij 	 * default value in case it is not specified. Either
699808d97ccSLinus Walleij 	 * value must not exceed the clock rate into the block,
700808d97ccSLinus Walleij 	 * of course.
701808d97ccSLinus Walleij 	 */
702808d97ccSLinus Walleij 	if (plat->f_max)
703808d97ccSLinus Walleij 		mmc->f_max = min(host->mclk, plat->f_max);
704808d97ccSLinus Walleij 	else
7051c6a0718SPierre Ossman 		mmc->f_max = min(host->mclk, fmax);
70664de0289SLinus Walleij 	dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
70764de0289SLinus Walleij 
70834e84f39SLinus Walleij #ifdef CONFIG_REGULATOR
70934e84f39SLinus Walleij 	/* If we're using the regulator framework, try to fetch a regulator */
71034e84f39SLinus Walleij 	host->vcc = regulator_get(&dev->dev, "vmmc");
71134e84f39SLinus Walleij 	if (IS_ERR(host->vcc))
71234e84f39SLinus Walleij 		host->vcc = NULL;
71334e84f39SLinus Walleij 	else {
71434e84f39SLinus Walleij 		int mask = mmc_regulator_get_ocrmask(host->vcc);
71534e84f39SLinus Walleij 
71634e84f39SLinus Walleij 		if (mask < 0)
71734e84f39SLinus Walleij 			dev_err(&dev->dev, "error getting OCR mask (%d)\n",
71834e84f39SLinus Walleij 				mask);
71934e84f39SLinus Walleij 		else {
72034e84f39SLinus Walleij 			host->mmc->ocr_avail = (u32) mask;
72134e84f39SLinus Walleij 			if (plat->ocr_mask)
72234e84f39SLinus Walleij 				dev_warn(&dev->dev,
72334e84f39SLinus Walleij 				 "Provided ocr_mask/setpower will not be used "
72434e84f39SLinus Walleij 				 "(using regulator instead)\n");
72534e84f39SLinus Walleij 		}
72634e84f39SLinus Walleij 	}
72734e84f39SLinus Walleij #endif
72834e84f39SLinus Walleij 	/* Fall back to platform data if no regulator is found */
72934e84f39SLinus Walleij 	if (host->vcc == NULL)
7301c6a0718SPierre Ossman 		mmc->ocr_avail = plat->ocr_mask;
7319e6c82cdSLinus Walleij 	mmc->caps = plat->capabilities;
7321c6a0718SPierre Ossman 
7331c6a0718SPierre Ossman 	/*
7341c6a0718SPierre Ossman 	 * We can do SGIO
7351c6a0718SPierre Ossman 	 */
7361c6a0718SPierre Ossman 	mmc->max_hw_segs = 16;
7371c6a0718SPierre Ossman 	mmc->max_phys_segs = NR_SG;
7381c6a0718SPierre Ossman 
7391c6a0718SPierre Ossman 	/*
74008458ef6SRabin Vincent 	 * Since only a certain number of bits are valid in the data length
74108458ef6SRabin Vincent 	 * register, we must ensure that we don't exceed 2^num-1 bytes in a
74208458ef6SRabin Vincent 	 * single request.
7431c6a0718SPierre Ossman 	 */
74408458ef6SRabin Vincent 	mmc->max_req_size = (1 << variant->datalength_bits) - 1;
7451c6a0718SPierre Ossman 
7461c6a0718SPierre Ossman 	/*
7471c6a0718SPierre Ossman 	 * Set the maximum segment size.  Since we aren't doing DMA
7481c6a0718SPierre Ossman 	 * (yet) we are only limited by the data length register.
7491c6a0718SPierre Ossman 	 */
7501c6a0718SPierre Ossman 	mmc->max_seg_size = mmc->max_req_size;
7511c6a0718SPierre Ossman 
7521c6a0718SPierre Ossman 	/*
7531c6a0718SPierre Ossman 	 * Block size can be up to 2048 bytes, but must be a power of two.
7541c6a0718SPierre Ossman 	 */
7551c6a0718SPierre Ossman 	mmc->max_blk_size = 2048;
7561c6a0718SPierre Ossman 
7571c6a0718SPierre Ossman 	/*
7581c6a0718SPierre Ossman 	 * No limit on the number of blocks transferred.
7591c6a0718SPierre Ossman 	 */
7601c6a0718SPierre Ossman 	mmc->max_blk_count = mmc->max_req_size;
7611c6a0718SPierre Ossman 
7621c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
7631c6a0718SPierre Ossman 
7641c6a0718SPierre Ossman 	writel(0, host->base + MMCIMASK0);
7651c6a0718SPierre Ossman 	writel(0, host->base + MMCIMASK1);
7661c6a0718SPierre Ossman 	writel(0xfff, host->base + MMCICLEAR);
7671c6a0718SPierre Ossman 
76889001446SRussell King 	if (gpio_is_valid(plat->gpio_cd)) {
76989001446SRussell King 		ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");
77089001446SRussell King 		if (ret == 0)
77189001446SRussell King 			ret = gpio_direction_input(plat->gpio_cd);
77289001446SRussell King 		if (ret == 0)
77389001446SRussell King 			host->gpio_cd = plat->gpio_cd;
77489001446SRussell King 		else if (ret != -ENOSYS)
77589001446SRussell King 			goto err_gpio_cd;
776148b8b39SRabin Vincent 
777148b8b39SRabin Vincent 		ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),
778148b8b39SRabin Vincent 					      mmci_cd_irq, 0,
779148b8b39SRabin Vincent 					      DRIVER_NAME " (cd)", host);
780148b8b39SRabin Vincent 		if (ret >= 0)
781148b8b39SRabin Vincent 			host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);
78289001446SRussell King 	}
78389001446SRussell King 	if (gpio_is_valid(plat->gpio_wp)) {
78489001446SRussell King 		ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
78589001446SRussell King 		if (ret == 0)
78689001446SRussell King 			ret = gpio_direction_input(plat->gpio_wp);
78789001446SRussell King 		if (ret == 0)
78889001446SRussell King 			host->gpio_wp = plat->gpio_wp;
78989001446SRussell King 		else if (ret != -ENOSYS)
79089001446SRussell King 			goto err_gpio_wp;
79189001446SRussell King 	}
79289001446SRussell King 
7934b8caec0SRabin Vincent 	if ((host->plat->status || host->gpio_cd != -ENOSYS)
7944b8caec0SRabin Vincent 	    && host->gpio_cd_irq < 0)
795148b8b39SRabin Vincent 		mmc->caps |= MMC_CAP_NEEDS_POLL;
796148b8b39SRabin Vincent 
7971c6a0718SPierre Ossman 	ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
7981c6a0718SPierre Ossman 	if (ret)
7991c6a0718SPierre Ossman 		goto unmap;
8001c6a0718SPierre Ossman 
8011c6a0718SPierre Ossman 	ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
8021c6a0718SPierre Ossman 	if (ret)
8031c6a0718SPierre Ossman 		goto irq0_free;
8041c6a0718SPierre Ossman 
8051c6a0718SPierre Ossman 	writel(MCI_IRQENABLE, host->base + MMCIMASK0);
8061c6a0718SPierre Ossman 
8071c6a0718SPierre Ossman 	amba_set_drvdata(dev, mmc);
8081c6a0718SPierre Ossman 
8091c6a0718SPierre Ossman 	mmc_add_host(mmc);
8101c6a0718SPierre Ossman 
81164de0289SLinus Walleij 	dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
8121c6a0718SPierre Ossman 		mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
8131c6a0718SPierre Ossman 		(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
8141c6a0718SPierre Ossman 
8151c6a0718SPierre Ossman 	return 0;
8161c6a0718SPierre Ossman 
8171c6a0718SPierre Ossman  irq0_free:
8181c6a0718SPierre Ossman 	free_irq(dev->irq[0], host);
8191c6a0718SPierre Ossman  unmap:
82089001446SRussell King 	if (host->gpio_wp != -ENOSYS)
82189001446SRussell King 		gpio_free(host->gpio_wp);
82289001446SRussell King  err_gpio_wp:
823148b8b39SRabin Vincent 	if (host->gpio_cd_irq >= 0)
824148b8b39SRabin Vincent 		free_irq(host->gpio_cd_irq, host);
82589001446SRussell King 	if (host->gpio_cd != -ENOSYS)
82689001446SRussell King 		gpio_free(host->gpio_cd);
82789001446SRussell King  err_gpio_cd:
8281c6a0718SPierre Ossman 	iounmap(host->base);
8291c6a0718SPierre Ossman  clk_disable:
8301c6a0718SPierre Ossman 	clk_disable(host->clk);
8311c6a0718SPierre Ossman  clk_free:
8321c6a0718SPierre Ossman 	clk_put(host->clk);
8331c6a0718SPierre Ossman  host_free:
8341c6a0718SPierre Ossman 	mmc_free_host(mmc);
8351c6a0718SPierre Ossman  rel_regions:
8361c6a0718SPierre Ossman 	amba_release_regions(dev);
8371c6a0718SPierre Ossman  out:
8381c6a0718SPierre Ossman 	return ret;
8391c6a0718SPierre Ossman }
8401c6a0718SPierre Ossman 
8416dc4a47aSLinus Walleij static int __devexit mmci_remove(struct amba_device *dev)
8421c6a0718SPierre Ossman {
8431c6a0718SPierre Ossman 	struct mmc_host *mmc = amba_get_drvdata(dev);
8441c6a0718SPierre Ossman 
8451c6a0718SPierre Ossman 	amba_set_drvdata(dev, NULL);
8461c6a0718SPierre Ossman 
8471c6a0718SPierre Ossman 	if (mmc) {
8481c6a0718SPierre Ossman 		struct mmci_host *host = mmc_priv(mmc);
8491c6a0718SPierre Ossman 
8501c6a0718SPierre Ossman 		mmc_remove_host(mmc);
8511c6a0718SPierre Ossman 
8521c6a0718SPierre Ossman 		writel(0, host->base + MMCIMASK0);
8531c6a0718SPierre Ossman 		writel(0, host->base + MMCIMASK1);
8541c6a0718SPierre Ossman 
8551c6a0718SPierre Ossman 		writel(0, host->base + MMCICOMMAND);
8561c6a0718SPierre Ossman 		writel(0, host->base + MMCIDATACTRL);
8571c6a0718SPierre Ossman 
8581c6a0718SPierre Ossman 		free_irq(dev->irq[0], host);
8591c6a0718SPierre Ossman 		free_irq(dev->irq[1], host);
8601c6a0718SPierre Ossman 
86189001446SRussell King 		if (host->gpio_wp != -ENOSYS)
86289001446SRussell King 			gpio_free(host->gpio_wp);
863148b8b39SRabin Vincent 		if (host->gpio_cd_irq >= 0)
864148b8b39SRabin Vincent 			free_irq(host->gpio_cd_irq, host);
86589001446SRussell King 		if (host->gpio_cd != -ENOSYS)
86689001446SRussell King 			gpio_free(host->gpio_cd);
86789001446SRussell King 
8681c6a0718SPierre Ossman 		iounmap(host->base);
8691c6a0718SPierre Ossman 		clk_disable(host->clk);
8701c6a0718SPierre Ossman 		clk_put(host->clk);
8711c6a0718SPierre Ossman 
87234e84f39SLinus Walleij 		if (regulator_is_enabled(host->vcc))
87334e84f39SLinus Walleij 			regulator_disable(host->vcc);
87434e84f39SLinus Walleij 		regulator_put(host->vcc);
87534e84f39SLinus Walleij 
8761c6a0718SPierre Ossman 		mmc_free_host(mmc);
8771c6a0718SPierre Ossman 
8781c6a0718SPierre Ossman 		amba_release_regions(dev);
8791c6a0718SPierre Ossman 	}
8801c6a0718SPierre Ossman 
8811c6a0718SPierre Ossman 	return 0;
8821c6a0718SPierre Ossman }
8831c6a0718SPierre Ossman 
8841c6a0718SPierre Ossman #ifdef CONFIG_PM
8851c6a0718SPierre Ossman static int mmci_suspend(struct amba_device *dev, pm_message_t state)
8861c6a0718SPierre Ossman {
8871c6a0718SPierre Ossman 	struct mmc_host *mmc = amba_get_drvdata(dev);
8881c6a0718SPierre Ossman 	int ret = 0;
8891c6a0718SPierre Ossman 
8901c6a0718SPierre Ossman 	if (mmc) {
8911c6a0718SPierre Ossman 		struct mmci_host *host = mmc_priv(mmc);
8921c6a0718SPierre Ossman 
8931a13f8faSMatt Fleming 		ret = mmc_suspend_host(mmc);
8941c6a0718SPierre Ossman 		if (ret == 0)
8951c6a0718SPierre Ossman 			writel(0, host->base + MMCIMASK0);
8961c6a0718SPierre Ossman 	}
8971c6a0718SPierre Ossman 
8981c6a0718SPierre Ossman 	return ret;
8991c6a0718SPierre Ossman }
9001c6a0718SPierre Ossman 
9011c6a0718SPierre Ossman static int mmci_resume(struct amba_device *dev)
9021c6a0718SPierre Ossman {
9031c6a0718SPierre Ossman 	struct mmc_host *mmc = amba_get_drvdata(dev);
9041c6a0718SPierre Ossman 	int ret = 0;
9051c6a0718SPierre Ossman 
9061c6a0718SPierre Ossman 	if (mmc) {
9071c6a0718SPierre Ossman 		struct mmci_host *host = mmc_priv(mmc);
9081c6a0718SPierre Ossman 
9091c6a0718SPierre Ossman 		writel(MCI_IRQENABLE, host->base + MMCIMASK0);
9101c6a0718SPierre Ossman 
9111c6a0718SPierre Ossman 		ret = mmc_resume_host(mmc);
9121c6a0718SPierre Ossman 	}
9131c6a0718SPierre Ossman 
9141c6a0718SPierre Ossman 	return ret;
9151c6a0718SPierre Ossman }
9161c6a0718SPierre Ossman #else
9171c6a0718SPierre Ossman #define mmci_suspend	NULL
9181c6a0718SPierre Ossman #define mmci_resume	NULL
9191c6a0718SPierre Ossman #endif
9201c6a0718SPierre Ossman 
9211c6a0718SPierre Ossman static struct amba_id mmci_ids[] = {
9221c6a0718SPierre Ossman 	{
9231c6a0718SPierre Ossman 		.id	= 0x00041180,
9241c6a0718SPierre Ossman 		.mask	= 0x000fffff,
9254956e109SRabin Vincent 		.data	= &variant_arm,
9261c6a0718SPierre Ossman 	},
9271c6a0718SPierre Ossman 	{
9281c6a0718SPierre Ossman 		.id	= 0x00041181,
9291c6a0718SPierre Ossman 		.mask	= 0x000fffff,
9304956e109SRabin Vincent 		.data	= &variant_arm,
9311c6a0718SPierre Ossman 	},
932cc30d60eSLinus Walleij 	/* ST Micro variants */
933cc30d60eSLinus Walleij 	{
934cc30d60eSLinus Walleij 		.id     = 0x00180180,
935cc30d60eSLinus Walleij 		.mask   = 0x00ffffff,
9364956e109SRabin Vincent 		.data	= &variant_u300,
937cc30d60eSLinus Walleij 	},
938cc30d60eSLinus Walleij 	{
939cc30d60eSLinus Walleij 		.id     = 0x00280180,
940cc30d60eSLinus Walleij 		.mask   = 0x00ffffff,
9414956e109SRabin Vincent 		.data	= &variant_u300,
9424956e109SRabin Vincent 	},
9434956e109SRabin Vincent 	{
9444956e109SRabin Vincent 		.id     = 0x00480180,
9454956e109SRabin Vincent 		.mask   = 0x00ffffff,
9464956e109SRabin Vincent 		.data	= &variant_ux500,
947cc30d60eSLinus Walleij 	},
9481c6a0718SPierre Ossman 	{ 0, 0 },
9491c6a0718SPierre Ossman };
9501c6a0718SPierre Ossman 
9511c6a0718SPierre Ossman static struct amba_driver mmci_driver = {
9521c6a0718SPierre Ossman 	.drv		= {
9531c6a0718SPierre Ossman 		.name	= DRIVER_NAME,
9541c6a0718SPierre Ossman 	},
9551c6a0718SPierre Ossman 	.probe		= mmci_probe,
9566dc4a47aSLinus Walleij 	.remove		= __devexit_p(mmci_remove),
9571c6a0718SPierre Ossman 	.suspend	= mmci_suspend,
9581c6a0718SPierre Ossman 	.resume		= mmci_resume,
9591c6a0718SPierre Ossman 	.id_table	= mmci_ids,
9601c6a0718SPierre Ossman };
9611c6a0718SPierre Ossman 
9621c6a0718SPierre Ossman static int __init mmci_init(void)
9631c6a0718SPierre Ossman {
9641c6a0718SPierre Ossman 	return amba_driver_register(&mmci_driver);
9651c6a0718SPierre Ossman }
9661c6a0718SPierre Ossman 
9671c6a0718SPierre Ossman static void __exit mmci_exit(void)
9681c6a0718SPierre Ossman {
9691c6a0718SPierre Ossman 	amba_driver_unregister(&mmci_driver);
9701c6a0718SPierre Ossman }
9711c6a0718SPierre Ossman 
9721c6a0718SPierre Ossman module_init(mmci_init);
9731c6a0718SPierre Ossman module_exit(mmci_exit);
9741c6a0718SPierre Ossman module_param(fmax, uint, 0444);
9751c6a0718SPierre Ossman 
9761c6a0718SPierre Ossman MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
9771c6a0718SPierre Ossman MODULE_LICENSE("GPL");
978