mmci.c revision 771dc157e06d69fcece0b2c8a29b9010345d8e9a
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
270f10482c668301c483acded13bf68780ad352b9Pierre Ossman *  linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
564de028948f449af17cf387f45a45f36ffd3c960Linus Walleij *  Copyright (C) 2010 ST-Ericsson AB.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/highmem.h>
20019a5f56ec195aceadada18aaaad0f67294bdaefNicolas Pitre#include <linux/log2.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h>
22a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/bus.h>
23f8ce25476d5f12ffa29b885e49c38cd95053437eRussell King#include <linux/clk.h>
24bd6dee6f30a0f6943df190b387b5f8fe98a848f3Jens Axboe#include <linux/scatterlist.h>
2589001446925d6da8785c3265a71316e34c6d15deRussell King#include <linux/gpio.h>
266ef297f86b62f187c59475784208f75c2ed8ccd8Linus Walleij#include <linux/amba/mmci.h>
2734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#include <linux/regulator/consumer.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29e9c091b47409255cefa1672041479d850b7b991aRussell King#include <asm/cacheflush.h>
307b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King#include <asm/div64.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
32c6b8fdad144bbb915d124ffd95011ad55730bf9fRussell King#include <asm/sizes.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mmci.h"
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "mmci-pl18x"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int fmax = 515633;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij/*
41a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij * This must be called with host->lock held
42a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij */
43a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleijstatic void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
44a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij{
45a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	u32 clk = 0;
46a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij
47a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	if (desired) {
48a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij		if (desired >= host->mclk) {
49a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij			clk = MCI_CLK_BYPASS;
50a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij			host->cclk = host->mclk;
51a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij		} else {
52a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij			clk = host->mclk / (2 * desired) - 1;
53a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij			if (clk >= 256)
54a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij				clk = 255;
55a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij			host->cclk = host->mclk / (2 * (clk + 1));
56a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij		}
57b43149c168ce4069ce8828b1ceb8f7eb42bc4b82Linus Walleij		if (host->hw_designer == AMBA_VENDOR_ST)
58771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij			clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */
59a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij		clk |= MCI_CLK_ENABLE;
60a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij		/* This hasn't proven to be worthwhile */
61a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij		/* clk |= MCI_CLK_PWRSAVE; */
62a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	}
63a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij
649e6c82cd3e1a739ef48bf8c1decc8e7a7d8de3acLinus Walleij	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
65771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij		clk |= MCI_4BIT_BUS;
66771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
67771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij		clk |= MCI_ST_8BIT_BUS;
689e6c82cd3e1a739ef48bf8c1decc8e7a7d8de3acLinus Walleij
69a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	writel(clk, host->base + MMCICLOCK);
70a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij}
71a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(0, host->base + MMCICOMMAND);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King	BUG_ON(host->data);
78e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->mrq = NULL;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmd = NULL;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mrq->data)
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mrq->data->bytes_xfered = host->data_xfered;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Need to drop the host lock here; mmc_request_done may call
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * back into the driver...
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&host->lock);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_request_done(host->mmc, mrq);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&host->lock);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_stop_data(struct mmci_host *host)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(0, host->base + MMCIDATACTRL);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(0, host->base + MMCIMASK1);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->data = NULL;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int datactrl, timeout, irqmask;
1047b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King	unsigned long long clks;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *base;
1063bc87f243f64c953717bea058f4b458a57fc1a29Russell King	int blksz_bits;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10864de028948f449af17cf387f45a45f36ffd3c960Linus Walleij	dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
10964de028948f449af17cf387f45a45f36ffd3c960Linus Walleij		data->blksz, data->blocks, data->flags);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->data = data;
1123bc87f243f64c953717bea058f4b458a57fc1a29Russell King	host->size = data->blksz;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->data_xfered = 0;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmci_init_sg(host, data);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1177b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King	clks = (unsigned long long)data->timeout_ns * host->cclk;
1187b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King	do_div(clks, 1000000000UL);
1197b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King
1207b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King	timeout = data->timeout_clks + (unsigned int)clks;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	base = host->base;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(timeout, base + MMCIDATATIMER);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(host->size, base + MMCIDATALENGTH);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1263bc87f243f64c953717bea058f4b458a57fc1a29Russell King	blksz_bits = ffs(data->blksz) - 1;
1273bc87f243f64c953717bea058f4b458a57fc1a29Russell King	BUG_ON(1 << blksz_bits != data->blksz);
1283bc87f243f64c953717bea058f4b458a57fc1a29Russell King
1293bc87f243f64c953717bea058f4b458a57fc1a29Russell King	datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->flags & MMC_DATA_READ) {
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		datactrl |= MCI_DPSM_DIRECTION;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irqmask = MCI_RXFIFOHALFFULLMASK;
1330425a14213f373595bd23cacdc675f2b973a28d4Russell King
1340425a14213f373595bd23cacdc675f2b973a28d4Russell King		/*
1350425a14213f373595bd23cacdc675f2b973a28d4Russell King		 * If we have less than a FIFOSIZE of bytes to transfer,
1360425a14213f373595bd23cacdc675f2b973a28d4Russell King		 * trigger a PIO interrupt as soon as any data is available.
1370425a14213f373595bd23cacdc675f2b973a28d4Russell King		 */
1380425a14213f373595bd23cacdc675f2b973a28d4Russell King		if (host->size < MCI_FIFOSIZE)
1390425a14213f373595bd23cacdc675f2b973a28d4Russell King			irqmask |= MCI_RXDATAAVLBLMASK;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * We don't actually need to include "FIFO empty" here
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * since its implicit in "FIFO half empty".
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irqmask = MCI_TXFIFOHALFEMPTYMASK;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(datactrl, base + MMCIDATACTRL);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(irqmask, base + MMCIMASK1);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *base = host->base;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15864de028948f449af17cf387f45a45f36ffd3c960Linus Walleij	dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    cmd->opcode, cmd->arg, cmd->flags);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(0, base + MMCICOMMAND);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(1);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c |= cmd->opcode | MCI_CPSM_ENABLE;
167e92251762d02a46177d4105d1744041e3f8bc465Russell King	if (cmd->flags & MMC_RSP_PRESENT) {
168e92251762d02a46177d4105d1744041e3f8bc465Russell King		if (cmd->flags & MMC_RSP_136)
169e92251762d02a46177d4105d1744041e3f8bc465Russell King			c |= MCI_CPSM_LONGRSP;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c |= MCI_CPSM_RESPONSE;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (/*interrupt*/0)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		c |= MCI_CPSM_INTERRUPT;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmd = cmd;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(cmd->arg, base + MMCIARGUMENT);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(c, base + MMCICOMMAND);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_data_irq(struct mmci_host *host, struct mmc_data *data,
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      unsigned int status)
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & MCI_DATABLOCKEND) {
1863bc87f243f64c953717bea058f4b458a57fc1a29Russell King		host->data_xfered += data->blksz;
187f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij#ifdef CONFIG_ARCH_U300
188f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		/*
189f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		 * On the U300 some signal or other is
190f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		 * badly routed so that a data write does
191f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		 * not properly terminate with a MCI_DATAEND
192f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		 * status flag. This quirk will make writes
193f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		 * work again.
194f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		 */
195f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij		if (data->flags & MMC_DATA_WRITE)
196f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij			status |= MCI_DATAEND;
197f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij#endif
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
20064de028948f449af17cf387f45a45f36ffd3c960Linus Walleij		dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & MCI_DATACRCFAIL)
20217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman			data->error = -EILSEQ;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (status & MCI_DATATIMEOUT)
20417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman			data->error = -ETIMEDOUT;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
20617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman			data->error = -EIO;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status |= MCI_DATAEND;
208e9c091b47409255cefa1672041479d850b7b991aRussell King
209e9c091b47409255cefa1672041479d850b7b991aRussell King		/*
210e9c091b47409255cefa1672041479d850b7b991aRussell King		 * We hit an error condition.  Ensure that any data
211e9c091b47409255cefa1672041479d850b7b991aRussell King		 * partially written to a page is properly coherent.
212e9c091b47409255cefa1672041479d850b7b991aRussell King		 */
213e9c091b47409255cefa1672041479d850b7b991aRussell King		if (host->sg_len && data->flags & MMC_DATA_READ)
214bd6dee6f30a0f6943df190b387b5f8fe98a848f3Jens Axboe			flush_dcache_page(sg_page(host->sg_ptr));
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & MCI_DATAEND) {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmci_stop_data(host);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!data->stop) {
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mmci_request_end(host, data->mrq);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mmci_start_command(host, data->stop, 0);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     unsigned int status)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *base = host->base;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmd = NULL;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->resp[0] = readl(base + MMCIRESPONSE0);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->resp[1] = readl(base + MMCIRESPONSE1);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->resp[2] = readl(base + MMCIRESPONSE2);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd->resp[3] = readl(base + MMCIRESPONSE3);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & MCI_CMDTIMEOUT) {
24117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		cmd->error = -ETIMEDOUT;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
24317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		cmd->error = -EILSEQ;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (!cmd->data || cmd->error) {
247e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King		if (host->data)
248e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King			mmci_stop_data(host);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmci_request_end(host, cmd->mrq);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmci_start_data(host, cmd->data);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *base = host->base;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *ptr = buffer;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status;
26026eed9a5c61edd93d88e147188d4feae6770174eLinus Walleij	int host_remain = host->size;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
26326eed9a5c61edd93d88e147188d4feae6770174eLinus Walleij		int count = host_remain - (readl(base + MMCIFIFOCNT) << 2);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count > remain)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count = remain;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count <= 0)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		readsl(base + MMCIFIFO, ptr, count >> 2);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr += count;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remain -= count;
27526eed9a5c61edd93d88e147188d4feae6770174eLinus Walleij		host_remain -= count;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (remain == 0)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = readl(base + MMCISTATUS);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (status & MCI_RXDATAAVLBL);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ptr - buffer;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *base = host->base;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *ptr = buffer;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int count, maxcnt;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = min(remain, maxcnt);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writesl(base + MMCIFIFO, ptr, count >> 2);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr += count;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remain -= count;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (remain == 0)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = readl(base + MMCISTATUS);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (status & MCI_TXFIFOHALFEMPTY);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ptr - buffer;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PIO data transfer IRQ handler.
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3147d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mmci_pio_irq(int irq, void *dev_id)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmci_host *host = dev_id;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *base = host->base;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = readl(base + MMCISTATUS);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32264de028948f449af17cf387f45a45f36ffd3c960Linus Walleij	dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long flags;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int remain, len;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char *buffer;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * For write, we only need to test the half-empty flag
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * here - if the FIFO is completely empty, then by
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * definition it is more than half empty.
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * For read, check for data available.
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Map the current scatter buffer.
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remain = host->sg_ptr->length - host->sg_off;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = 0;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & MCI_RXACTIVE)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = mmci_pio_read(host, buffer, remain);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & MCI_TXACTIVE)
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = mmci_pio_write(host, buffer, remain, status);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Unmap the buffer.
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
354f3e2628bed0d5a88ced8239b35f1534557f9631cEvgeniy Polyakov		mmci_kunmap_atomic(host, buffer, &flags);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->sg_off += len;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->size -= len;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remain -= len;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (remain)
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
363e9c091b47409255cefa1672041479d850b7b991aRussell King		/*
364e9c091b47409255cefa1672041479d850b7b991aRussell King		 * If we were reading, and we have completed this
365e9c091b47409255cefa1672041479d850b7b991aRussell King		 * page, ensure that the data cache is coherent.
366e9c091b47409255cefa1672041479d850b7b991aRussell King		 */
367e9c091b47409255cefa1672041479d850b7b991aRussell King		if (status & MCI_RXACTIVE)
368bd6dee6f30a0f6943df190b387b5f8fe98a848f3Jens Axboe			flush_dcache_page(sg_page(host->sg_ptr));
369e9c091b47409255cefa1672041479d850b7b991aRussell King
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!mmci_next_sg(host))
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = readl(base + MMCISTATUS);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (1);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we're nearing the end of the read, switch to
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * "any data available" mode.
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we run out of data, disable the data IRQs; this
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * prevents a race where the FIFO becomes empty before
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the chip itself has disabled the data path, and
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * stops us racing with our data end IRQ.
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host->size == 0) {
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(0, base + MMCIMASK1);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle completion of command and data transfers.
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4007d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mmci_irq(int irq, void *dev_id)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmci_host *host = dev_id;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&host->lock);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct mmc_command *cmd;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct mmc_data *data;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = readl(host->base + MMCISTATUS);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status &= readl(host->base + MMCIMASK0);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(status, host->base + MMCICLEAR);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41664de028948f449af17cf387f45a45f36ffd3c960Linus Walleij		dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data = host->data;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mmci_data_irq(host, data, status);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd = host->cmd;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mmci_cmd_irq(host, cmd, status);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 1;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (status);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&host->lock);
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(ret);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmci_host *host = mmc_priv(mmc);
4389e9430213f85ebdaf40026ec790295420efd0f91Linus Walleij	unsigned long flags;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON(host->mrq != NULL);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
442019a5f56ec195aceadada18aaaad0f67294bdaefNicolas Pitre	if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
44364de028948f449af17cf387f45a45f36ffd3c960Linus Walleij		dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
44464de028948f449af17cf387f45a45f36ffd3c960Linus Walleij			mrq->data->blksz);
445255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman		mrq->cmd->error = -EINVAL;
446255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman		mmc_request_done(mmc, mrq);
447255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman		return;
448255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman	}
449255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman
4509e9430213f85ebdaf40026ec790295420efd0f91Linus Walleij	spin_lock_irqsave(&host->lock, flags);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->mrq = mrq;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mrq->data && mrq->data->flags & MMC_DATA_READ)
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmci_start_data(host, mrq->data);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmci_start_command(host, mrq->cmd, 0);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4599e9430213f85ebdaf40026ec790295420efd0f91Linus Walleij	spin_unlock_irqrestore(&host->lock, flags);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmci_host *host = mmc_priv(mmc);
465a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	u32 pwr = 0;
466a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	unsigned long flags;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ios->power_mode) {
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MMC_POWER_OFF:
47034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		if(host->vcc &&
47134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		   regulator_is_enabled(host->vcc))
47234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			regulator_disable(host->vcc);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MMC_POWER_UP:
47534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#ifdef CONFIG_REGULATOR
47634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		if (host->vcc)
47734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			/* This implicitly enables the regulator */
47834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			mmc_regulator_set_ocr(host->vcc, ios->vdd);
47934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#endif
48034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		/*
48134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		 * The translate_vdd function is not used if you have
48234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		 * an external regulator, or your design is really weird.
48334e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		 * Using it would mean sending in power control BOTH using
48434e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		 * a regulator AND the 4 MMCIPWR bits. If we don't have
48534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		 * a regulator, we might have some other platform specific
48634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		 * power control behind this translate function.
48734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		 */
48834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		if (!host->vcc && host->plat->translate_vdd)
48934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
490cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		/* The ST version does not have this, fall through to POWER_ON */
491f17a1f06d2fa93f4825be572622eb02c4894db4eLinus Walleij		if (host->hw_designer != AMBA_VENDOR_ST) {
492cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			pwr |= MCI_PWR_UP;
493cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			break;
494cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		}
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case MMC_POWER_ON:
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pwr |= MCI_PWR_ON;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
500cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
501f17a1f06d2fa93f4825be572622eb02c4894db4eLinus Walleij		if (host->hw_designer != AMBA_VENDOR_ST)
502cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			pwr |= MCI_ROD;
503cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		else {
504cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			/*
505cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			 * The ST Micro variant use the ROD bit for something
506cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			 * else and only has OD (Open Drain).
507cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			 */
508cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij			pwr |= MCI_OD;
509cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		}
510cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij	}
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
512a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	spin_lock_irqsave(&host->lock, flags);
513a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij
514a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	mmci_set_clkreg(host, ios->clock);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host->pwr != pwr) {
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->pwr = pwr;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(pwr, host->base + MMCIPOWER);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
520a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij
521a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij	spin_unlock_irqrestore(&host->lock, flags);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52489001446925d6da8785c3265a71316e34c6d15deRussell Kingstatic int mmci_get_ro(struct mmc_host *mmc)
52589001446925d6da8785c3265a71316e34c6d15deRussell King{
52689001446925d6da8785c3265a71316e34c6d15deRussell King	struct mmci_host *host = mmc_priv(mmc);
52789001446925d6da8785c3265a71316e34c6d15deRussell King
52889001446925d6da8785c3265a71316e34c6d15deRussell King	if (host->gpio_wp == -ENOSYS)
52989001446925d6da8785c3265a71316e34c6d15deRussell King		return -ENOSYS;
53089001446925d6da8785c3265a71316e34c6d15deRussell King
53189001446925d6da8785c3265a71316e34c6d15deRussell King	return gpio_get_value(host->gpio_wp);
53289001446925d6da8785c3265a71316e34c6d15deRussell King}
53389001446925d6da8785c3265a71316e34c6d15deRussell King
53489001446925d6da8785c3265a71316e34c6d15deRussell Kingstatic int mmci_get_cd(struct mmc_host *mmc)
53589001446925d6da8785c3265a71316e34c6d15deRussell King{
53689001446925d6da8785c3265a71316e34c6d15deRussell King	struct mmci_host *host = mmc_priv(mmc);
53789001446925d6da8785c3265a71316e34c6d15deRussell King	unsigned int status;
53889001446925d6da8785c3265a71316e34c6d15deRussell King
53989001446925d6da8785c3265a71316e34c6d15deRussell King	if (host->gpio_cd == -ENOSYS)
54089001446925d6da8785c3265a71316e34c6d15deRussell King		status = host->plat->status(mmc_dev(host->mmc));
54189001446925d6da8785c3265a71316e34c6d15deRussell King	else
54289001446925d6da8785c3265a71316e34c6d15deRussell King		status = gpio_get_value(host->gpio_cd);
54389001446925d6da8785c3265a71316e34c6d15deRussell King
54489001446925d6da8785c3265a71316e34c6d15deRussell King	return !status;
54589001446925d6da8785c3265a71316e34c6d15deRussell King}
54689001446925d6da8785c3265a71316e34c6d15deRussell King
547ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops mmci_ops = {
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.request	= mmci_request,
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_ios	= mmci_set_ios,
55089001446925d6da8785c3265a71316e34c6d15deRussell King	.get_ro		= mmci_get_ro,
55189001446925d6da8785c3265a71316e34c6d15deRussell King	.get_cd		= mmci_get_cd,
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_check_status(unsigned long data)
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmci_host *host = (struct mmci_host *)data;
55789001446925d6da8785c3265a71316e34c6d15deRussell King	unsigned int status = mmci_get_cd(host->mmc);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status ^ host->oldstat)
5608dc003359cc3996abad9e53a7b2280b272610283Richard Purdie		mmc_detect_change(host->mmc, 0);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->oldstat = status;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mod_timer(&host->timer, jiffies + HZ);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56603fbdb15c14e9746c63168e3ff2c64b9c8336d33Alessandro Rubinistatic int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5686ef297f86b62f187c59475784208f75c2ed8ccd8Linus Walleij	struct mmci_platform_data *plat = dev->dev.platform_data;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmci_host *host;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_host *mmc;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* must have platform data */
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!plat) {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = amba_request_regions(dev, DRIVER_NAME);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!mmc) {
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto rel_regions;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host = mmc_priv(mmc);
5904ea580f1db62c5419e6690878fd61a740f3aae8eRabin Vincent	host->mmc = mmc;
591012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King
59289001446925d6da8785c3265a71316e34c6d15deRussell King	host->gpio_wp = -ENOSYS;
59389001446925d6da8785c3265a71316e34c6d15deRussell King	host->gpio_cd = -ENOSYS;
59489001446925d6da8785c3265a71316e34c6d15deRussell King
595012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King	host->hw_designer = amba_manf(dev);
596012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King	host->hw_revision = amba_rev(dev);
59764de028948f449af17cf387f45a45f36ffd3c960Linus Walleij	dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
59864de028948f449af17cf387f45a45f36ffd3c960Linus Walleij	dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
599012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King
600ee569c43e340202fb0ba427c57b77568a32b9a3aRussell King	host->clk = clk_get(&dev->dev, NULL);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(host->clk)) {
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = PTR_ERR(host->clk);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->clk = NULL;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto host_free;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = clk_enable(host->clk);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
609a8d3584a2df28827094f6338cde1303c467bc1f0Russell King		goto clk_free;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->plat = plat;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->mclk = clk_get_rate(host->clk);
613c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij	/*
614c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij	 * According to the spec, mclk is max 100 MHz,
615c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij	 * so we try to adjust the clock down to this,
616c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij	 * (if possible).
617c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij	 */
618c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij	if (host->mclk > 100000000) {
619c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij		ret = clk_set_rate(host->clk, 100000000);
620c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij		if (ret < 0)
621c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij			goto clk_disable;
622c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij		host->mclk = clk_get_rate(host->clk);
62364de028948f449af17cf387f45a45f36ffd3c960Linus Walleij		dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
62464de028948f449af17cf387f45a45f36ffd3c960Linus Walleij			host->mclk);
625c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij	}
626dc890c2dcd63a90de68ee5f0253eefbb89d725f0Linus Walleij	host->base = ioremap(dev->res.start, resource_size(&dev->res));
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!host->base) {
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto clk_disable;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc->ops = &mmci_ops;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc->f_min = (host->mclk + 511) / 512;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc->f_max = min(host->mclk, fmax);
63564de028948f449af17cf387f45a45f36ffd3c960Linus Walleij	dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
63664de028948f449af17cf387f45a45f36ffd3c960Linus Walleij
63734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#ifdef CONFIG_REGULATOR
63834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij	/* If we're using the regulator framework, try to fetch a regulator */
63934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij	host->vcc = regulator_get(&dev->dev, "vmmc");
64034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij	if (IS_ERR(host->vcc))
64134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		host->vcc = NULL;
64234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij	else {
64334e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		int mask = mmc_regulator_get_ocrmask(host->vcc);
64434e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij
64534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		if (mask < 0)
64634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			dev_err(&dev->dev, "error getting OCR mask (%d)\n",
64734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij				mask);
64834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		else {
64934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			host->mmc->ocr_avail = (u32) mask;
65034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			if (plat->ocr_mask)
65134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij				dev_warn(&dev->dev,
65234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij				 "Provided ocr_mask/setpower will not be used "
65334e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij				 "(using regulator instead)\n");
65434e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		}
65534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij	}
65634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#endif
65734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij	/* Fall back to platform data if no regulator is found */
65834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij	if (host->vcc == NULL)
65934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		mmc->ocr_avail = plat->ocr_mask;
6609e6c82cd3e1a739ef48bf8c1decc8e7a7d8de3acLinus Walleij	mmc->caps = plat->capabilities;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We can do SGIO
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc->max_hw_segs = 16;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc->max_phys_segs = NR_SG;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Since we only have a 16-bit data length register, we must
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ensure that we don't exceed 2^16-1 bytes in a single request.
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
67255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	mmc->max_req_size = 65535;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Set the maximum segment size.  Since we aren't doing DMA
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (yet) we are only limited by the data length register.
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
67855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	mmc->max_seg_size = mmc->max_req_size;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
680fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	/*
681fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	 * Block size can be up to 2048 bytes, but must be a power of two.
682fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	 */
683fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	mmc->max_blk_size = 2048;
684fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman
68555db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	/*
68655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 * No limit on the number of blocks transferred.
68755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 */
68855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	mmc->max_blk_count = mmc->max_req_size;
68955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&host->lock);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(0, host->base + MMCIMASK0);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(0, host->base + MMCIMASK1);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(0xfff, host->base + MMCICLEAR);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69689001446925d6da8785c3265a71316e34c6d15deRussell King	if (gpio_is_valid(plat->gpio_cd)) {
69789001446925d6da8785c3265a71316e34c6d15deRussell King		ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");
69889001446925d6da8785c3265a71316e34c6d15deRussell King		if (ret == 0)
69989001446925d6da8785c3265a71316e34c6d15deRussell King			ret = gpio_direction_input(plat->gpio_cd);
70089001446925d6da8785c3265a71316e34c6d15deRussell King		if (ret == 0)
70189001446925d6da8785c3265a71316e34c6d15deRussell King			host->gpio_cd = plat->gpio_cd;
70289001446925d6da8785c3265a71316e34c6d15deRussell King		else if (ret != -ENOSYS)
70389001446925d6da8785c3265a71316e34c6d15deRussell King			goto err_gpio_cd;
70489001446925d6da8785c3265a71316e34c6d15deRussell King	}
70589001446925d6da8785c3265a71316e34c6d15deRussell King	if (gpio_is_valid(plat->gpio_wp)) {
70689001446925d6da8785c3265a71316e34c6d15deRussell King		ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
70789001446925d6da8785c3265a71316e34c6d15deRussell King		if (ret == 0)
70889001446925d6da8785c3265a71316e34c6d15deRussell King			ret = gpio_direction_input(plat->gpio_wp);
70989001446925d6da8785c3265a71316e34c6d15deRussell King		if (ret == 0)
71089001446925d6da8785c3265a71316e34c6d15deRussell King			host->gpio_wp = plat->gpio_wp;
71189001446925d6da8785c3265a71316e34c6d15deRussell King		else if (ret != -ENOSYS)
71289001446925d6da8785c3265a71316e34c6d15deRussell King			goto err_gpio_wp;
71389001446925d6da8785c3265a71316e34c6d15deRussell King	}
71489001446925d6da8785c3265a71316e34c6d15deRussell King
715dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner	ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto unmap;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
719dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner	ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto irq0_free;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(MCI_IRQENABLE, host->base + MMCIMASK0);
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_set_drvdata(dev, mmc);
72689001446925d6da8785c3265a71316e34c6d15deRussell King	host->oldstat = mmci_get_cd(host->mmc);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_add_host(mmc);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
73064de028948f449af17cf387f45a45f36ffd3c960Linus Walleij	dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
731d366b6436386875b1310ce8f70e3f9dea4647bacRussell King		mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
732e29419fffceb8ec36def3c922040e1ca7bcd3de5Greg Kroah-Hartman		(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&host->timer);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->timer.data = (unsigned long)host;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->timer.function = mmci_check_status;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->timer.expires = jiffies + HZ;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&host->timer);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq0_free:
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(dev->irq[0], host);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unmap:
74589001446925d6da8785c3265a71316e34c6d15deRussell King	if (host->gpio_wp != -ENOSYS)
74689001446925d6da8785c3265a71316e34c6d15deRussell King		gpio_free(host->gpio_wp);
74789001446925d6da8785c3265a71316e34c6d15deRussell King err_gpio_wp:
74889001446925d6da8785c3265a71316e34c6d15deRussell King	if (host->gpio_cd != -ENOSYS)
74989001446925d6da8785c3265a71316e34c6d15deRussell King		gpio_free(host->gpio_cd);
75089001446925d6da8785c3265a71316e34c6d15deRussell King err_gpio_cd:
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(host->base);
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable:
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clk_disable(host->clk);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_free:
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clk_put(host->clk);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_free:
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_free_host(mmc);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rel_regions:
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_release_regions(dev);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7646dc4a47a0cf423879b505af0e29997fca4088630Linus Walleijstatic int __devexit mmci_remove(struct amba_device *dev)
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_host *mmc = amba_get_drvdata(dev);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_set_drvdata(dev, NULL);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mmc) {
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct mmci_host *host = mmc_priv(mmc);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_timer_sync(&host->timer);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_remove_host(mmc);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(0, host->base + MMCIMASK0);
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(0, host->base + MMCIMASK1);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(0, host->base + MMCICOMMAND);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(0, host->base + MMCIDATACTRL);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(dev->irq[0], host);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(dev->irq[1], host);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
78689001446925d6da8785c3265a71316e34c6d15deRussell King		if (host->gpio_wp != -ENOSYS)
78789001446925d6da8785c3265a71316e34c6d15deRussell King			gpio_free(host->gpio_wp);
78889001446925d6da8785c3265a71316e34c6d15deRussell King		if (host->gpio_cd != -ENOSYS)
78989001446925d6da8785c3265a71316e34c6d15deRussell King			gpio_free(host->gpio_cd);
79089001446925d6da8785c3265a71316e34c6d15deRussell King
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iounmap(host->base);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clk_disable(host->clk);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clk_put(host->clk);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
79534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		if (regulator_is_enabled(host->vcc))
79634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij			regulator_disable(host->vcc);
79734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij		regulator_put(host->vcc);
79834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_free_host(mmc);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		amba_release_regions(dev);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM
808e5378ca8c0ab684bd9339dc6827dd5a042f9e6fcPavel Machekstatic int mmci_suspend(struct amba_device *dev, pm_message_t state)
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_host *mmc = amba_get_drvdata(dev);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mmc) {
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct mmci_host *host = mmc_priv(mmc);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = mmc_suspend_host(mmc, state);
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret == 0)
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			writel(0, host->base + MMCIMASK0);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_resume(struct amba_device *dev)
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_host *mmc = amba_get_drvdata(dev);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mmc) {
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct mmci_host *host = mmc_priv(mmc);
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(MCI_IRQENABLE, host->base + MMCIMASK0);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = mmc_resume_host(mmc);
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_suspend	NULL
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_resume	NULL
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_id mmci_ids[] = {
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id	= 0x00041180,
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.mask	= 0x000fffff,
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id	= 0x00041181,
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.mask	= 0x000fffff,
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
853cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij	/* ST Micro variants */
854cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij	{
855cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		.id     = 0x00180180,
856cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		.mask   = 0x00ffffff,
857cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij	},
858cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij	{
859cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		.id     = 0x00280180,
860cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij		.mask   = 0x00ffffff,
861cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij	},
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, 0 },
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_driver mmci_driver = {
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.drv		= {
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.name	= DRIVER_NAME,
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= mmci_probe,
8706dc4a47a0cf423879b505af0e29997fca4088630Linus Walleij	.remove		= __devexit_p(mmci_remove),
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.suspend	= mmci_suspend,
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.resume		= mmci_resume,
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table	= mmci_ids,
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init mmci_init(void)
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return amba_driver_register(&mmci_driver);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit mmci_exit(void)
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	amba_driver_unregister(&mmci_driver);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mmci_init);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mmci_exit);
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(fmax, uint, 0444);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
892