11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
270f10482c668301c483acded13bf68780ad352b9Pierre Ossman *  linux/drivers/mmc/host/pxa.c - PXA MMCI driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2003 Russell King, All Rights Reserved.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This hardware is really sick:
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - No way to clear interrupts.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Have to turn off the clock whenever we touch the device.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Doesn't tell you how many data blocks were transferred.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Yuck!
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	1 and 3 byte data transfers not supported
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	max block length up to 1023
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
22d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h>
26ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King#include <linux/clk.h>
27ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King#include <linux/err.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h>
2905678a96de2e97fdfd4b817478840ad6a02ea1d8Russell King#include <linux/io.h>
308385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro#include <linux/regulator/consumer.h>
31b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik#include <linux/gpio.h>
325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sizes.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3605678a96de2e97fdfd4b817478840ad6a02ea1d8Russell King#include <mach/hardware.h>
377ebc8d56f407184a457dd5fc739cf39e423a25aaEric Miao#include <mach/dma.h>
38a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/mmc.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pxamci.h"
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME	"pxa2xx-mci"
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NR_SG	1
45d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King#define CLKRT_OFF	(~0)
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang#define mmc_has_26MHz()		(cpu_is_pxa300() || cpu_is_pxa310() \
48fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang				|| cpu_is_pxa935())
49fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pxamci_host {
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_host		*mmc;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t		lock;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct resource		*res;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem		*base;
55ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	struct clk		*clk;
56ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	unsigned long		clkrate;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			irq;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			dma;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int		clkrt;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int		cmdat;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int		imask;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int		power_mode;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pxamci_platform_data *pdata;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_request	*mrq;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_command	*cmd;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_data		*data;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t		sg_dma;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pxa_dma_desc	*sg_cpu;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int		dma_len;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int		dma_dir;
749a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	unsigned int		dma_drcmrrx;
759a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	unsigned int		dma_drcmrtx;
768385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro
778385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	struct regulator	*vcc;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
808385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeirostatic inline void pxamci_init_ocr(struct pxamci_host *host)
818385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro{
828385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro#ifdef CONFIG_REGULATOR
838385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
848385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro
858385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	if (IS_ERR(host->vcc))
868385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro		host->vcc = NULL;
878385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	else {
888385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro		host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
898385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro		if (host->pdata && host->pdata->ocr_mask)
908385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro			dev_warn(mmc_dev(host->mmc),
918385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro				"ocr_mask/setpower will not be used\n");
928385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	}
938385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro#endif
948385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	if (host->vcc == NULL) {
958385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro		/* fall-back to platform data */
968385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro		host->mmc->ocr_avail = host->pdata ?
978385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro			host->pdata->ocr_mask :
988385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro			MMC_VDD_32_33 | MMC_VDD_33_34;
998385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	}
1008385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro}
1018385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro
10299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleijstatic inline int pxamci_set_power(struct pxamci_host *host,
10399fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij				    unsigned char power_mode,
10499fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij				    unsigned int vdd)
1058385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro{
106b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	int on;
107b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik
10899fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij	if (host->vcc) {
10999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		int ret;
11099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij
11199fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		if (power_mode == MMC_POWER_UP) {
11299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
11399fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			if (ret)
11499fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij				return ret;
11599fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		} else if (power_mode == MMC_POWER_OFF) {
11699fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
11799fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			if (ret)
11899fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij				return ret;
11999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		}
12099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij	}
121b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (!host->vcc && host->pdata &&
122b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	    gpio_is_valid(host->pdata->gpio_power)) {
123b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		on = ((1 << vdd) & host->pdata->ocr_mask);
124b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		gpio_set_value(host->pdata->gpio_power,
125b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			       !!on ^ host->pdata->gpio_power_invert);
126b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	}
1278385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	if (!host->vcc && host->pdata && host->pdata->setpower)
1288385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro		host->pdata->setpower(mmc_dev(host->mmc), vdd);
12999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij
13099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij	return 0;
1318385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro}
1328385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_stop_clock(struct pxamci_host *host)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long timeout = 10000;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int v;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(STOP_CLOCK, host->base + MMC_STRPCL);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			v = readl(host->base + MMC_STAT);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(v & STAT_CLK_EN))
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(1);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} while (timeout--);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (v & STAT_CLK_EN)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&host->lock, flags);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->imask &= ~mask;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(host->imask, host->base + MMC_I_MASK);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&host->lock, flags);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&host->lock, flags);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->imask |= mask;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(host->imask, host->base + MMC_I_MASK);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&host->lock, flags);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int nob = data->blocks;
1763d63abe56be2147891b3438cb3bd37a9be72bda7Russell King	unsigned long long clks;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int timeout;
17897f8571e663c808ad2d01a396627235167291556Philipp Zabel	bool dalgn = 0;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 dcmd;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->data = data;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->flags & MMC_DATA_STREAM)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nob = 0xffff;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(nob, host->base + MMC_NOB);
1882c171bf13423dc5293188cea7f6c2da1720926e2Pavel Pisa	writel(data->blksz, host->base + MMC_BLKLEN);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
190ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	clks = (unsigned long long)data->timeout_ns * host->clkrate;
1913d63abe56be2147891b3438cb3bd37a9be72bda7Russell King	do_div(clks, 1000000000UL);
1923d63abe56be2147891b3438cb3bd37a9be72bda7Russell King	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel((timeout + 255) / 256, host->base + MMC_RDTO);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->flags & MMC_DATA_READ) {
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->dma_dir = DMA_FROM_DEVICE;
1977eeff4814224646c896303ba2c2b7ac3c4240cd2Matt Reimer		dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
1989a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		DRCMR(host->dma_drcmrtx) = 0;
1999a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->dma_dir = DMA_TO_DEVICE;
2027eeff4814224646c896303ba2c2b7ac3c4240cd2Matt Reimer		dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
2039a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		DRCMR(host->dma_drcmrrx) = 0;
2049a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   host->dma_dir);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < host->dma_len; i++) {
213c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre		unsigned int length = sg_dma_len(&data->sg[i]);
214c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre		host->sg_cpu[i].dcmd = dcmd | length;
215c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre		if (length & 31 && !(data->flags & MMC_DATA_READ))
216c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre			host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
21797f8571e663c808ad2d01a396627235167291556Philipp Zabel		/* Not aligned to 8-byte boundary? */
21897f8571e663c808ad2d01a396627235167291556Philipp Zabel		if (sg_dma_address(&data->sg[i]) & 0x7)
21997f8571e663c808ad2d01a396627235167291556Philipp Zabel			dalgn = 1;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->flags & MMC_DATA_READ) {
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(struct pxa_dma_desc);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23397f8571e663c808ad2d01a396627235167291556Philipp Zabel	/*
23497f8571e663c808ad2d01a396627235167291556Philipp Zabel	 * The PXA27x DMA controller encounters overhead when working with
23597f8571e663c808ad2d01a396627235167291556Philipp Zabel	 * unaligned (to 8-byte boundaries) data, so switch on byte alignment
23697f8571e663c808ad2d01a396627235167291556Philipp Zabel	 * mode only if we have unaligned data.
23797f8571e663c808ad2d01a396627235167291556Philipp Zabel	 */
23897f8571e663c808ad2d01a396627235167291556Philipp Zabel	if (dalgn)
23997f8571e663c808ad2d01a396627235167291556Philipp Zabel		DALGN |= (1 << host->dma);
24097f8571e663c808ad2d01a396627235167291556Philipp Zabel	else
2414fe16897c59882420d66f2d503106653d026ed6cKarl Beldan		DALGN &= ~(1 << host->dma);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DDADR(host->dma) = host->sg_dma;
243b6018958a57f6621d6979c4384e42a3df636beedCliff Brake
244b6018958a57f6621d6979c4384e42a3df636beedCliff Brake	/*
245b6018958a57f6621d6979c4384e42a3df636beedCliff Brake	 * workaround for erratum #91:
246b6018958a57f6621d6979c4384e42a3df636beedCliff Brake	 * only start DMA now if we are doing a read,
247b6018958a57f6621d6979c4384e42a3df636beedCliff Brake	 * otherwise we wait until CMD/RESP has finished
248b6018958a57f6621d6979c4384e42a3df636beedCliff Brake	 * before starting DMA.
249b6018958a57f6621d6979c4384e42a3df636beedCliff Brake	 */
250b6018958a57f6621d6979c4384e42a3df636beedCliff Brake	if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
251b6018958a57f6621d6979c4384e42a3df636beedCliff Brake		DCSR(host->dma) = DCSR_RUN;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON(host->cmd != NULL);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmd = cmd;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd->flags & MMC_RSP_BUSY)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmdat |= CMDAT_BUSY;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
262e92251762d02a46177d4105d1744041e3f8bc465Russell King#define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
263e92251762d02a46177d4105d1744041e3f8bc465Russell King	switch (RSP_TYPE(mmc_resp_type(cmd))) {
2646f949909e8f9e5d7e5584dc48d9a5e060c52aed1Philip Langdale	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmdat |= CMDAT_RESP_SHORT;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
267e92251762d02a46177d4105d1744041e3f8bc465Russell King	case RSP_TYPE(MMC_RSP_R3):
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmdat |= CMDAT_RESP_R3;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
270e92251762d02a46177d4105d1744041e3f8bc465Russell King	case RSP_TYPE(MMC_RSP_R2):
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmdat |= CMDAT_RESP_R2;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(cmd->opcode, host->base + MMC_CMD);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(cmd->arg >> 16, host->base + MMC_ARGH);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(cmdat, host->base + MMC_CMDAT);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(host->clkrt, host->base + MMC_CLKRT);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(START_CLOCK, host->base + MMC_STRPCL);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxamci_enable_irq(host, END_CMD_RES);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->mrq = NULL;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmd = NULL;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->data = NULL;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_request_done(host->mmc, mrq);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_command *cmd = host->cmd;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 v;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cmd)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmd = NULL;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Did I mention this is Sick.  We always need to
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * discard the upper 8 bits of the first 16-bit word.
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	v = readl(host->base + MMC_RES) & 0xffff;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 4; i++) {
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		v = w2;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (stat & STAT_TIME_OUT_RESPONSE) {
32017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		cmd->error = -ETIMEDOUT;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * workaround for erratum #42:
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Intel PXA27x Family Processor Specification Update Rev 001
32590e07d9f54c61449dd48eff82e2354d0124d4f7eNicolas Pitre		 * A bogus CRC error can appear if the msb of a 136 bit
32690e07d9f54c61449dd48eff82e2354d0124d4f7eNicolas Pitre		 * response is a one.
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
328e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake		if (cpu_is_pxa27x() &&
329e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake		    (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000))
33090e07d9f54c61449dd48eff82e2354d0124d4f7eNicolas Pitre			pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
331e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake		else
332e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake			cmd->error = -EILSEQ;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxamci_disable_irq(host, END_CMD_RES);
33617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (host->data && !cmd->error) {
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxamci_enable_irq(host, DATA_TRAN_DONE);
338b6018958a57f6621d6979c4384e42a3df636beedCliff Brake		/*
339b6018958a57f6621d6979c4384e42a3df636beedCliff Brake		 * workaround for erratum #91, if doing write
340b6018958a57f6621d6979c4384e42a3df636beedCliff Brake		 * enable DMA late
341b6018958a57f6621d6979c4384e42a3df636beedCliff Brake		 */
342b6018958a57f6621d6979c4384e42a3df636beedCliff Brake		if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
343b6018958a57f6621d6979c4384e42a3df636beedCliff Brake			DCSR(host->dma) = DCSR_RUN;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxamci_finish_request(host, host->mrq);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_data *data = host->data;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!data)
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DCSR(host->dma) = 0;
359c00a46abd4d45a67ff62f4ff6d4f839dff38b877Vernon Sauder	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     host->dma_dir);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (stat & STAT_READ_TIME_OUT)
36317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		data->error = -ETIMEDOUT;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
36517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		data->error = -EILSEQ;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * There appears to be a hardware design bug here.  There seems to
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * be no way to find out how much data was transferred to the card.
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This means that if there was an error on any block, we mark all
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * data blocks as being in error.
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
37317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (!data->error)
3742c171bf13423dc5293188cea7f6c2da1720926e2Pavel Pisa		data->bytes_xfered = data->blocks * data->blksz;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->bytes_xfered = 0;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxamci_disable_irq(host, DATA_TRAN_DONE);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->data = NULL;
38158741e8b3603e56c3699550e8bc89cb136329343Russell King	if (host->mrq->stop) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxamci_stop_clock(host);
383df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu		pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxamci_finish_request(host, host->mrq);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3917d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pxamci_irq(int irq, void *devid)
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pxamci_host *host = devid;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int ireg;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int handled = 0;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39781ab570f65395f09962f4bca0d89403f8911c071Bridge Wu	ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ireg) {
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned stat = readl(host->base + MMC_STAT);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
402d78e9079af7526c4661ff484322094832776ef41Russell King		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ireg & END_CMD_RES)
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			handled |= pxamci_cmd_done(host, stat);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ireg & DATA_TRAN_DONE)
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			handled |= pxamci_data_done(host, stat);
4085d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu		if (ireg & SDIO_INT) {
4095d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu			mmc_signal_sdio_irq(host->mmc);
4105d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu			handled = 1;
4115d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu		}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(handled);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pxamci_host *host = mmc_priv(mmc);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int cmdat;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON(host->mrq != NULL);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->mrq = mrq;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxamci_stop_clock(host);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmdat = host->cmdat;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->cmdat &= ~CMDAT_INIT;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mrq->data) {
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxamci_setup_data(host, mrq->data);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmdat &= ~CMDAT_BUSY;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mrq->data->flags & MMC_DATA_WRITE)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cmdat |= CMDAT_WRITE;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mrq->data->flags & MMC_DATA_STREAM)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cmdat |= CMDAT_STREAM;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxamci_start_cmd(host, mrq->cmd, cmdat);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
446e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdiestatic int pxamci_get_ro(struct mmc_host *mmc)
447e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie{
448e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie	struct pxamci_host *host = mmc_priv(mmc);
449e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie
450b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) {
451b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (host->pdata->gpio_card_ro_invert)
452b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			return !gpio_get_value(host->pdata->gpio_card_ro);
453b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		else
454b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			return gpio_get_value(host->pdata->gpio_card_ro);
455b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	}
456e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie	if (host->pdata && host->pdata->get_ro)
45708f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov		return !!host->pdata->get_ro(mmc_dev(mmc));
45808f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov	/*
45908f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov	 * Board doesn't support read only detection; let the mmc core
46008f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov	 * decide what to do.
46108f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov	 */
46208f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov	return -ENOSYS;
463e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie}
464e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pxamci_host *host = mmc_priv(mmc);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ios->clock) {
470ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King		unsigned long rate = host->clkrate;
471ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King		unsigned int clk = rate / ios->clock;
472ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King
473d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King		if (host->clkrt == CLKRT_OFF)
474d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King			clk_enable(host->clk);
475d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King
47664eb036af42d3816364c4db49d93be3a4614389cBridge Wu		if (ios->clock == 26000000) {
477fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang			/* to support 26MHz */
47864eb036af42d3816364c4db49d93be3a4614389cBridge Wu			host->clkrt = 7;
47964eb036af42d3816364c4db49d93be3a4614389cBridge Wu		} else {
48064eb036af42d3816364c4db49d93be3a4614389cBridge Wu			/* to handle (19.5MHz, 26MHz) */
48164eb036af42d3816364c4db49d93be3a4614389cBridge Wu			if (!clk)
48264eb036af42d3816364c4db49d93be3a4614389cBridge Wu				clk = 1;
48364eb036af42d3816364c4db49d93be3a4614389cBridge Wu
48464eb036af42d3816364c4db49d93be3a4614389cBridge Wu			/*
48564eb036af42d3816364c4db49d93be3a4614389cBridge Wu			 * clk might result in a lower divisor than we
48664eb036af42d3816364c4db49d93be3a4614389cBridge Wu			 * desire.  check for that condition and adjust
48764eb036af42d3816364c4db49d93be3a4614389cBridge Wu			 * as appropriate.
48864eb036af42d3816364c4db49d93be3a4614389cBridge Wu			 */
48964eb036af42d3816364c4db49d93be3a4614389cBridge Wu			if (rate / clk > ios->clock)
49064eb036af42d3816364c4db49d93be3a4614389cBridge Wu				clk <<= 1;
49164eb036af42d3816364c4db49d93be3a4614389cBridge Wu			host->clkrt = fls(clk) - 1;
49264eb036af42d3816364c4db49d93be3a4614389cBridge Wu		}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * we write clkrt on the next command
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxamci_stop_clock(host);
499d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King		if (host->clkrt != CLKRT_OFF) {
500d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King			host->clkrt = CLKRT_OFF;
501d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King			clk_disable(host->clk);
502d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King		}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host->power_mode != ios->power_mode) {
50699fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		int ret;
50799fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host->power_mode = ios->power_mode;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
51199fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		if (ret) {
51299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			dev_err(mmc_dev(mmc), "unable to set power\n");
51399fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			/*
51499fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			 * The .set_ios() function in the mmc_host_ops
51599fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			 * struct return void, and failing to set the
51699fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			 * power should be rare so we print an error and
51799fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			 * return here.
51899fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			 */
51999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij			return;
52099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ios->power_mode == MMC_POWER_ON)
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			host->cmdat |= CMDAT_INIT;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
526df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu	if (ios->bus_width == MMC_BUS_WIDTH_4)
527df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu		host->cmdat |= CMDAT_SD_4DAT;
528df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu	else
529df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu		host->cmdat &= ~CMDAT_SD_4DAT;
530df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu
53199fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij	dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
53299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij		host->clkrt, host->cmdat);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5355d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wustatic void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
5365d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu{
5375d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	struct pxamci_host *pxa_host = mmc_priv(host);
5385d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu
5395d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	if (enable)
5405d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu		pxamci_enable_irq(pxa_host, SDIO_INT);
5415d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	else
5425d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu		pxamci_disable_irq(pxa_host, SDIO_INT);
5435d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu}
5445d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu
545ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops pxamci_ops = {
5465d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	.request		= pxamci_request,
5475d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	.get_ro			= pxamci_get_ro,
5485d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	.set_ios		= pxamci_set_ios,
5495d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	.enable_sdio_irq	= pxamci_enable_sdio_irq,
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5527d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pxamci_dma_irq(int dma, void *devid)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
554c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre	struct pxamci_host *host = devid;
555c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre	int dcsr = DCSR(dma);
556c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre	DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
557c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre
558c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre	if (dcsr & DCSR_ENDINTR) {
559c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
560c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre	} else {
561a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S		pr_err("%s: DMA error on channel %d (DCSR=%#x)\n",
562c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre		       mmc_hostname(host->mmc), dma, dcsr);
563c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre		host->data->error = -EIO;
564c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre		pxamci_data_done(host, 0);
565c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre	}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5687d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pxamci_detect_irq(int irq, void *devid)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
570c26971cbb39727b0b692c6236f890ba13046a663Richard Purdie	struct pxamci_host *host = mmc_priv(devid);
571c26971cbb39727b0b692c6236f890ba13046a663Richard Purdie
572f97cab28b1895ecb0aa317cc785bb209f57fc1e8Eric Miao	mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms));
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5763ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int pxamci_probe(struct platform_device *pdev)
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mmc_host *mmc;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pxamci_host *host = NULL;
5809a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	struct resource *r, *dmarx, *dmatx;
581b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irq = platform_get_irq(pdev, 0);
585489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel	if (!r || irq < 0)
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!r)
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5923ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!mmc) {
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc->ops = &pxamci_ops;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We can do SG-DMA, but we don't because we never know how much
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * data we successfully wrote to the card.
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
604a36274e0184193e393fb82957925c3981a6b0477Martin K. Petersen	mmc->max_segs = NR_SG;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Our hardware DMA can handle a maximum of one page per SG entry.
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc->max_seg_size = PAGE_SIZE;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	/*
612fe2dc44eac1223a0e92859242f58fd2a58a6f8faNicolas Pitre	 * Block length register is only 10 bits before PXA27x.
613fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	 */
6140ffcbfd54ea81ca24c0749f55ca4fcf3e2bdc23eEric Miao	mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048;
615fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman
61655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	/*
61755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 * Block count register is 16 bits.
61855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 */
61955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	mmc->max_blk_count = 65535;
62055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host = mmc_priv(mmc);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->mmc = mmc;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->dma = -1;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->pdata = pdev->dev.platform_data;
625d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King	host->clkrt = CLKRT_OFF;
626ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King
627e0d8b13ae1e3ea747620580b6f777992148de182Russell King	host->clk = clk_get(&pdev->dev, NULL);
628ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	if (IS_ERR(host->clk)) {
629ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King		ret = PTR_ERR(host->clk);
630ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King		host->clk = NULL;
631ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King		goto out;
632ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	}
633ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King
634ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	host->clkrate = clk_get_rate(host->clk);
635ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King
636ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	/*
637ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	 * Calculate minimum clock rate, rounding up.
638ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	 */
639ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King	mmc->f_min = (host->clkrate + 63) / 64;
640fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang	mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
641ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King
6428385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro	pxamci_init_ocr(host);
6438385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro
644df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu	mmc->caps = 0;
6455d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	host->cmdat = 0;
6460ffcbfd54ea81ca24c0749f55ca4fcf3e2bdc23eEric Miao	if (!cpu_is_pxa25x()) {
6475d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
6485d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu		host->cmdat |= CMDAT_SDIO_INT_EN;
649fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang		if (mmc_has_26MHz())
65064eb036af42d3816364c4db49d93be3a4614389cBridge Wu			mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
65164eb036af42d3816364c4db49d93be3a4614389cBridge Wu				     MMC_CAP_SD_HIGHSPEED;
6525d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu	}
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6543ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!host->sg_cpu) {
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&host->lock);
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->res = r;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->irq = irq;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->imask = MMC_I_MASK_ALL;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->base = ioremap(r->start, SZ_4K);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!host->base) {
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ensure that the host controller is shut down, and setup
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * with our defaults.
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxamci_stop_clock(host);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(0, host->base + MMC_SPI);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(64, host->base + MMC_RESTO);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(host->imask, host->base + MMC_I_MASK);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    pxamci_dma_irq, host);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host->dma < 0) {
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EBUSY;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6913ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_set_drvdata(pdev, mmc);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6939a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
6949a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	if (!dmarx) {
6959a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		ret = -ENXIO;
6969a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		goto out;
6979a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	}
6989a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	host->dma_drcmrrx = dmarx->start;
6999a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu
7009a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
7019a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	if (!dmatx) {
7029a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		ret = -ENXIO;
7039a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		goto out;
7049a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	}
7059a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu	host->dma_drcmrtx = dmatx->start;
7069a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu
707b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (host->pdata) {
708b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		gpio_cd = host->pdata->gpio_card_detect;
709b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		gpio_ro = host->pdata->gpio_card_ro;
710b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		gpio_power = host->pdata->gpio_power;
711b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	}
712b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (gpio_is_valid(gpio_power)) {
713b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		ret = gpio_request(gpio_power, "mmc card power");
714b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (ret) {
715b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power);
716b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			goto out;
717b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		}
718b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		gpio_direction_output(gpio_power,
719b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik				      host->pdata->gpio_power_invert);
720b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	}
721b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (gpio_is_valid(gpio_ro)) {
722b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		ret = gpio_request(gpio_ro, "mmc card read only");
723b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (ret) {
72448f029542f1219eb50ade5e24b1b2799bd057413Antonio Ospite			dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
725b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			goto err_gpio_ro;
726b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		}
727b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		gpio_direction_input(gpio_ro);
728b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	}
729b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (gpio_is_valid(gpio_cd)) {
730b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		ret = gpio_request(gpio_cd, "mmc card detect");
731b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (ret) {
73248f029542f1219eb50ade5e24b1b2799bd057413Antonio Ospite			dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
733b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			goto err_gpio_cd;
734b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		}
735b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		gpio_direction_input(gpio_cd);
736b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik
737b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq,
738b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
739b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik				  "mmc card detect", mmc);
740b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (ret) {
741b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			dev_err(&pdev->dev, "failed to request card detect IRQ\n");
742b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			goto err_request_irq;
743b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		}
744b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	}
745b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host->pdata && host->pdata->init)
7473ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
749b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (gpio_is_valid(gpio_power) && host->pdata->setpower)
750b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n");
751b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
752b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n");
753b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mmc_add_host(mmc);
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
758b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmikerr_request_irq:
759b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	gpio_free(gpio_cd);
760b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmikerr_gpio_cd:
761b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	gpio_free(gpio_ro);
762b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmikerr_gpio_ro:
763b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	gpio_free(gpio_power);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (host) {
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (host->dma >= 0)
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pxa_free_dma(host->dma);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (host->base)
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iounmap(host->base);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (host->sg_cpu)
7713ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
772ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King		if (host->clk)
773ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King			clk_put(host->clk);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mmc)
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_free_host(mmc);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_resource(r);
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7813ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int pxamci_remove(struct platform_device *pdev)
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7833ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct mmc_host *mmc = platform_get_drvdata(pdev);
784b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik	int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7863ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_set_drvdata(pdev, NULL);
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mmc) {
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pxamci_host *host = mmc_priv(mmc);
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7915d6b1edf8ccc4b7e4e77dff3fc80882833d6186eDaniel Mack		mmc_remove_host(mmc);
7925d6b1edf8ccc4b7e4e77dff3fc80882833d6186eDaniel Mack
793b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (host->pdata) {
794b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			gpio_cd = host->pdata->gpio_card_detect;
795b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			gpio_ro = host->pdata->gpio_card_ro;
796b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			gpio_power = host->pdata->gpio_power;
797b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		}
798b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (gpio_is_valid(gpio_cd)) {
799b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			free_irq(gpio_to_irq(gpio_cd), mmc);
800b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			gpio_free(gpio_cd);
801b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		}
802b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (gpio_is_valid(gpio_ro))
803b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			gpio_free(gpio_ro);
804b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik		if (gpio_is_valid(gpio_power))
805b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik			gpio_free(gpio_power);
8068385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro		if (host->vcc)
8078385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro			regulator_put(host->vcc);
8088385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (host->pdata && host->pdata->exit)
8103ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King			host->pdata->exit(&pdev->dev, mmc);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxamci_stop_clock(host);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       host->base + MMC_I_MASK);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8179a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		DRCMR(host->dma_drcmrrx) = 0;
8189a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu		DRCMR(host->dma_drcmrtx) = 0;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(host->irq, host);
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxa_free_dma(host->dma);
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iounmap(host->base);
8233ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
825ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King		clk_put(host->clk);
826ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_resource(host->res);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mmc_free_host(mmc);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM
83533264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoportstatic int pxamci_suspend(struct device *dev)
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
83733264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport	struct mmc_host *mmc = dev_get_drvdata(dev);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8409480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King	if (mmc)
8411a13f8fa76c880be41d6b1e6a2b44404bcbfdf9eMatt Fleming		ret = mmc_suspend_host(mmc);
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
84633264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoportstatic int pxamci_resume(struct device *dev)
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
84833264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport	struct mmc_host *mmc = dev_get_drvdata(dev);
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8519480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King	if (mmc)
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = mmc_resume_host(mmc);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
85633264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport
857471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops pxamci_pm_ops = {
85833264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport	.suspend	= pxamci_suspend,
85933264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport	.resume		= pxamci_resume,
86033264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport};
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8633ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver pxamci_driver = {
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= pxamci_probe,
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove		= pxamci_remove,
8663ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
8673ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= DRIVER_NAME,
868bc65c724d5a2c61539b2c52680941505152fcf30Kay Sievers		.owner	= THIS_MODULE,
86933264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport#ifdef CONFIG_PM
87033264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport		.pm	= &pxamci_pm_ops,
87133264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport#endif
8723ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
875d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(pxamci_driver);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
879bc65c724d5a2c61539b2c52680941505152fcf30Kay SieversMODULE_ALIAS("platform:pxa2xx-mci");
880