xref: /openbmc/linux/drivers/mmc/host/pxamci.c (revision 38a8dda9)
11c6a0718SPierre Ossman /*
270f10482SPierre Ossman  *  linux/drivers/mmc/host/pxa.c - PXA MMCI driver
31c6a0718SPierre Ossman  *
41c6a0718SPierre Ossman  *  Copyright (C) 2003 Russell King, All Rights Reserved.
51c6a0718SPierre Ossman  *
61c6a0718SPierre Ossman  * This program is free software; you can redistribute it and/or modify
71c6a0718SPierre Ossman  * it under the terms of the GNU General Public License version 2 as
81c6a0718SPierre Ossman  * published by the Free Software Foundation.
91c6a0718SPierre Ossman  *
101c6a0718SPierre Ossman  *  This hardware is really sick:
111c6a0718SPierre Ossman  *   - No way to clear interrupts.
121c6a0718SPierre Ossman  *   - Have to turn off the clock whenever we touch the device.
131c6a0718SPierre Ossman  *   - Doesn't tell you how many data blocks were transferred.
141c6a0718SPierre Ossman  *  Yuck!
151c6a0718SPierre Ossman  *
161c6a0718SPierre Ossman  *	1 and 3 byte data transfers not supported
171c6a0718SPierre Ossman  *	max block length up to 1023
181c6a0718SPierre Ossman  */
191c6a0718SPierre Ossman #include <linux/module.h>
201c6a0718SPierre Ossman #include <linux/init.h>
211c6a0718SPierre Ossman #include <linux/ioport.h>
221c6a0718SPierre Ossman #include <linux/platform_device.h>
231c6a0718SPierre Ossman #include <linux/delay.h>
241c6a0718SPierre Ossman #include <linux/interrupt.h>
256464b714SDaniel Mack #include <linux/dmaengine.h>
261c6a0718SPierre Ossman #include <linux/dma-mapping.h>
27ebebd9b0SRussell King #include <linux/clk.h>
28ebebd9b0SRussell King #include <linux/err.h>
291c6a0718SPierre Ossman #include <linux/mmc/host.h>
30fd546ee6SRobert Jarzmik #include <linux/mmc/slot-gpio.h>
3105678a96SRussell King #include <linux/io.h>
328385f9cbSDaniel Ribeiro #include <linux/regulator/consumer.h>
33b405db6cSRobert Jarzmik #include <linux/gpio.h>
345a0e3ad6STejun Heo #include <linux/gfp.h>
35e6027b46SDaniel Mack #include <linux/of.h>
36e6027b46SDaniel Mack #include <linux/of_gpio.h>
37e6027b46SDaniel Mack #include <linux/of_device.h>
381c6a0718SPierre Ossman 
391c6a0718SPierre Ossman #include <asm/sizes.h>
401c6a0718SPierre Ossman 
4105678a96SRussell King #include <mach/hardware.h>
42293b2da1SArnd Bergmann #include <linux/platform_data/mmc-pxamci.h>
431c6a0718SPierre Ossman 
441c6a0718SPierre Ossman #include "pxamci.h"
451c6a0718SPierre Ossman 
461c6a0718SPierre Ossman #define DRIVER_NAME	"pxa2xx-mci"
471c6a0718SPierre Ossman 
481c6a0718SPierre Ossman #define NR_SG	1
49d8cb70d1SRussell King #define CLKRT_OFF	(~0)
501c6a0718SPierre Ossman 
51fa3f9938SHaojian Zhuang #define mmc_has_26MHz()		(cpu_is_pxa300() || cpu_is_pxa310() \
52fa3f9938SHaojian Zhuang 				|| cpu_is_pxa935())
53fa3f9938SHaojian Zhuang 
541c6a0718SPierre Ossman struct pxamci_host {
551c6a0718SPierre Ossman 	struct mmc_host		*mmc;
561c6a0718SPierre Ossman 	spinlock_t		lock;
571c6a0718SPierre Ossman 	struct resource		*res;
581c6a0718SPierre Ossman 	void __iomem		*base;
59ebebd9b0SRussell King 	struct clk		*clk;
60ebebd9b0SRussell King 	unsigned long		clkrate;
611c6a0718SPierre Ossman 	unsigned int		clkrt;
621c6a0718SPierre Ossman 	unsigned int		cmdat;
631c6a0718SPierre Ossman 	unsigned int		imask;
641c6a0718SPierre Ossman 	unsigned int		power_mode;
6538a8dda9SDaniel Mack 	unsigned long		detect_delay_ms;
661c6a0718SPierre Ossman 	struct pxamci_platform_data *pdata;
671c6a0718SPierre Ossman 
681c6a0718SPierre Ossman 	struct mmc_request	*mrq;
691c6a0718SPierre Ossman 	struct mmc_command	*cmd;
701c6a0718SPierre Ossman 	struct mmc_data		*data;
711c6a0718SPierre Ossman 
726464b714SDaniel Mack 	struct dma_chan		*dma_chan_rx;
736464b714SDaniel Mack 	struct dma_chan		*dma_chan_tx;
746464b714SDaniel Mack 	dma_cookie_t		dma_cookie;
751c6a0718SPierre Ossman 	unsigned int		dma_len;
761c6a0718SPierre Ossman 	unsigned int		dma_dir;
771c6a0718SPierre Ossman };
781c6a0718SPierre Ossman 
7961951fd6SDaniel Mack static int pxamci_init_ocr(struct pxamci_host *host)
808385f9cbSDaniel Ribeiro {
8161951fd6SDaniel Mack 	struct mmc_host *mmc = host->mmc;
8261951fd6SDaniel Mack 	int ret;
838385f9cbSDaniel Ribeiro 
8461951fd6SDaniel Mack 	ret = mmc_regulator_get_supply(mmc);
8561951fd6SDaniel Mack 	if (ret < 0)
8661951fd6SDaniel Mack 		return ret;
8761951fd6SDaniel Mack 
8861951fd6SDaniel Mack 	if (IS_ERR(mmc->supply.vmmc)) {
898385f9cbSDaniel Ribeiro 		/* fall-back to platform data */
9061951fd6SDaniel Mack 		mmc->ocr_avail = host->pdata ?
918385f9cbSDaniel Ribeiro 			host->pdata->ocr_mask :
928385f9cbSDaniel Ribeiro 			MMC_VDD_32_33 | MMC_VDD_33_34;
938385f9cbSDaniel Ribeiro 	}
9461951fd6SDaniel Mack 
9561951fd6SDaniel Mack 	return 0;
968385f9cbSDaniel Ribeiro }
978385f9cbSDaniel Ribeiro 
9899fc5131SLinus Walleij static inline int pxamci_set_power(struct pxamci_host *host,
9999fc5131SLinus Walleij 				    unsigned char power_mode,
10099fc5131SLinus Walleij 				    unsigned int vdd)
1018385f9cbSDaniel Ribeiro {
10261951fd6SDaniel Mack 	struct mmc_host *mmc = host->mmc;
10361951fd6SDaniel Mack 	struct regulator *supply = mmc->supply.vmmc;
104b405db6cSRobert Jarzmik 	int on;
105b405db6cSRobert Jarzmik 
10661951fd6SDaniel Mack 	if (!IS_ERR(supply))
10761951fd6SDaniel Mack 		return mmc_regulator_set_ocr(mmc, supply, vdd);
10899fc5131SLinus Walleij 
10961951fd6SDaniel Mack 	if (host->pdata &&
110b405db6cSRobert Jarzmik 	    gpio_is_valid(host->pdata->gpio_power)) {
111b405db6cSRobert Jarzmik 		on = ((1 << vdd) & host->pdata->ocr_mask);
112b405db6cSRobert Jarzmik 		gpio_set_value(host->pdata->gpio_power,
113b405db6cSRobert Jarzmik 			       !!on ^ host->pdata->gpio_power_invert);
114b405db6cSRobert Jarzmik 	}
11561951fd6SDaniel Mack 
11661951fd6SDaniel Mack 	if (host->pdata && host->pdata->setpower)
117a829abf8SArnd Bergmann 		return host->pdata->setpower(mmc_dev(host->mmc), vdd);
11899fc5131SLinus Walleij 
11999fc5131SLinus Walleij 	return 0;
1208385f9cbSDaniel Ribeiro }
1218385f9cbSDaniel Ribeiro 
1221c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host)
1231c6a0718SPierre Ossman {
1241c6a0718SPierre Ossman 	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
1251c6a0718SPierre Ossman 		unsigned long timeout = 10000;
1261c6a0718SPierre Ossman 		unsigned int v;
1271c6a0718SPierre Ossman 
1281c6a0718SPierre Ossman 		writel(STOP_CLOCK, host->base + MMC_STRPCL);
1291c6a0718SPierre Ossman 
1301c6a0718SPierre Ossman 		do {
1311c6a0718SPierre Ossman 			v = readl(host->base + MMC_STAT);
1321c6a0718SPierre Ossman 			if (!(v & STAT_CLK_EN))
1331c6a0718SPierre Ossman 				break;
1341c6a0718SPierre Ossman 			udelay(1);
1351c6a0718SPierre Ossman 		} while (timeout--);
1361c6a0718SPierre Ossman 
1371c6a0718SPierre Ossman 		if (v & STAT_CLK_EN)
1381c6a0718SPierre Ossman 			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
1391c6a0718SPierre Ossman 	}
1401c6a0718SPierre Ossman }
1411c6a0718SPierre Ossman 
1421c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
1431c6a0718SPierre Ossman {
1441c6a0718SPierre Ossman 	unsigned long flags;
1451c6a0718SPierre Ossman 
1461c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
1471c6a0718SPierre Ossman 	host->imask &= ~mask;
1481c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1491c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1501c6a0718SPierre Ossman }
1511c6a0718SPierre Ossman 
1521c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
1531c6a0718SPierre Ossman {
1541c6a0718SPierre Ossman 	unsigned long flags;
1551c6a0718SPierre Ossman 
1561c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
1571c6a0718SPierre Ossman 	host->imask |= mask;
1581c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1591c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1601c6a0718SPierre Ossman }
1611c6a0718SPierre Ossman 
1626464b714SDaniel Mack static void pxamci_dma_irq(void *param);
1636464b714SDaniel Mack 
1641c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
1651c6a0718SPierre Ossman {
1666464b714SDaniel Mack 	struct dma_async_tx_descriptor *tx;
1676464b714SDaniel Mack 	enum dma_data_direction direction;
1686464b714SDaniel Mack 	struct dma_slave_config	config;
1696464b714SDaniel Mack 	struct dma_chan *chan;
1701c6a0718SPierre Ossman 	unsigned int nob = data->blocks;
1711c6a0718SPierre Ossman 	unsigned long long clks;
1721c6a0718SPierre Ossman 	unsigned int timeout;
1736464b714SDaniel Mack 	int ret;
1741c6a0718SPierre Ossman 
1751c6a0718SPierre Ossman 	host->data = data;
1761c6a0718SPierre Ossman 
1771c6a0718SPierre Ossman 	writel(nob, host->base + MMC_NOB);
1781c6a0718SPierre Ossman 	writel(data->blksz, host->base + MMC_BLKLEN);
1791c6a0718SPierre Ossman 
180ebebd9b0SRussell King 	clks = (unsigned long long)data->timeout_ns * host->clkrate;
1811c6a0718SPierre Ossman 	do_div(clks, 1000000000UL);
1821c6a0718SPierre Ossman 	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
1831c6a0718SPierre Ossman 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
1841c6a0718SPierre Ossman 
1856464b714SDaniel Mack 	memset(&config, 0, sizeof(config));
1866464b714SDaniel Mack 	config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1876464b714SDaniel Mack 	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1886464b714SDaniel Mack 	config.src_addr = host->res->start + MMC_RXFIFO;
1896464b714SDaniel Mack 	config.dst_addr = host->res->start + MMC_TXFIFO;
1906464b714SDaniel Mack 	config.src_maxburst = 32;
1916464b714SDaniel Mack 	config.dst_maxburst = 32;
1926464b714SDaniel Mack 
1931c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ) {
1941c6a0718SPierre Ossman 		host->dma_dir = DMA_FROM_DEVICE;
1956464b714SDaniel Mack 		direction = DMA_DEV_TO_MEM;
1966464b714SDaniel Mack 		chan = host->dma_chan_rx;
1971c6a0718SPierre Ossman 	} else {
1981c6a0718SPierre Ossman 		host->dma_dir = DMA_TO_DEVICE;
1996464b714SDaniel Mack 		direction = DMA_MEM_TO_DEV;
2006464b714SDaniel Mack 		chan = host->dma_chan_tx;
2011c6a0718SPierre Ossman 	}
2021c6a0718SPierre Ossman 
2036464b714SDaniel Mack 	config.direction = direction;
2041c6a0718SPierre Ossman 
2056464b714SDaniel Mack 	ret = dmaengine_slave_config(chan, &config);
2066464b714SDaniel Mack 	if (ret < 0) {
2076464b714SDaniel Mack 		dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
2086464b714SDaniel Mack 		return;
2096464b714SDaniel Mack 	}
2106464b714SDaniel Mack 
2116464b714SDaniel Mack 	host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
2121c6a0718SPierre Ossman 				   host->dma_dir);
2131c6a0718SPierre Ossman 
2146464b714SDaniel Mack 	tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
2156464b714SDaniel Mack 				     DMA_PREP_INTERRUPT);
2166464b714SDaniel Mack 	if (!tx) {
2176464b714SDaniel Mack 		dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
2186464b714SDaniel Mack 		return;
2191c6a0718SPierre Ossman 	}
2201c6a0718SPierre Ossman 
2216464b714SDaniel Mack 	if (!(data->flags & MMC_DATA_READ)) {
2226464b714SDaniel Mack 		tx->callback = pxamci_dma_irq;
2236464b714SDaniel Mack 		tx->callback_param = host;
2246464b714SDaniel Mack 	}
2256464b714SDaniel Mack 
2266464b714SDaniel Mack 	host->dma_cookie = dmaengine_submit(tx);
227b6018958SCliff Brake 
228b6018958SCliff Brake 	/*
229b6018958SCliff Brake 	 * workaround for erratum #91:
230b6018958SCliff Brake 	 * only start DMA now if we are doing a read,
231b6018958SCliff Brake 	 * otherwise we wait until CMD/RESP has finished
232b6018958SCliff Brake 	 * before starting DMA.
233b6018958SCliff Brake 	 */
234b6018958SCliff Brake 	if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
2356464b714SDaniel Mack 		dma_async_issue_pending(chan);
2361c6a0718SPierre Ossman }
2371c6a0718SPierre Ossman 
2381c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
2391c6a0718SPierre Ossman {
2401c6a0718SPierre Ossman 	WARN_ON(host->cmd != NULL);
2411c6a0718SPierre Ossman 	host->cmd = cmd;
2421c6a0718SPierre Ossman 
2431c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_BUSY)
2441c6a0718SPierre Ossman 		cmdat |= CMDAT_BUSY;
2451c6a0718SPierre Ossman 
2461c6a0718SPierre Ossman #define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
2471c6a0718SPierre Ossman 	switch (RSP_TYPE(mmc_resp_type(cmd))) {
2481c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
2491c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_SHORT;
2501c6a0718SPierre Ossman 		break;
2511c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R3):
2521c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R3;
2531c6a0718SPierre Ossman 		break;
2541c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R2):
2551c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R2;
2561c6a0718SPierre Ossman 		break;
2571c6a0718SPierre Ossman 	default:
2581c6a0718SPierre Ossman 		break;
2591c6a0718SPierre Ossman 	}
2601c6a0718SPierre Ossman 
2611c6a0718SPierre Ossman 	writel(cmd->opcode, host->base + MMC_CMD);
2621c6a0718SPierre Ossman 	writel(cmd->arg >> 16, host->base + MMC_ARGH);
2631c6a0718SPierre Ossman 	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
2641c6a0718SPierre Ossman 	writel(cmdat, host->base + MMC_CMDAT);
2651c6a0718SPierre Ossman 	writel(host->clkrt, host->base + MMC_CLKRT);
2661c6a0718SPierre Ossman 
2671c6a0718SPierre Ossman 	writel(START_CLOCK, host->base + MMC_STRPCL);
2681c6a0718SPierre Ossman 
2691c6a0718SPierre Ossman 	pxamci_enable_irq(host, END_CMD_RES);
2701c6a0718SPierre Ossman }
2711c6a0718SPierre Ossman 
2721c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
2731c6a0718SPierre Ossman {
2741c6a0718SPierre Ossman 	host->mrq = NULL;
2751c6a0718SPierre Ossman 	host->cmd = NULL;
2761c6a0718SPierre Ossman 	host->data = NULL;
2771c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
2781c6a0718SPierre Ossman }
2791c6a0718SPierre Ossman 
2801c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
2811c6a0718SPierre Ossman {
2821c6a0718SPierre Ossman 	struct mmc_command *cmd = host->cmd;
2831c6a0718SPierre Ossman 	int i;
2841c6a0718SPierre Ossman 	u32 v;
2851c6a0718SPierre Ossman 
2861c6a0718SPierre Ossman 	if (!cmd)
2871c6a0718SPierre Ossman 		return 0;
2881c6a0718SPierre Ossman 
2891c6a0718SPierre Ossman 	host->cmd = NULL;
2901c6a0718SPierre Ossman 
2911c6a0718SPierre Ossman 	/*
2921c6a0718SPierre Ossman 	 * Did I mention this is Sick.  We always need to
2931c6a0718SPierre Ossman 	 * discard the upper 8 bits of the first 16-bit word.
2941c6a0718SPierre Ossman 	 */
2951c6a0718SPierre Ossman 	v = readl(host->base + MMC_RES) & 0xffff;
2961c6a0718SPierre Ossman 	for (i = 0; i < 4; i++) {
2971c6a0718SPierre Ossman 		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
2981c6a0718SPierre Ossman 		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
2991c6a0718SPierre Ossman 		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
3001c6a0718SPierre Ossman 		v = w2;
3011c6a0718SPierre Ossman 	}
3021c6a0718SPierre Ossman 
3031c6a0718SPierre Ossman 	if (stat & STAT_TIME_OUT_RESPONSE) {
30417b0429dSPierre Ossman 		cmd->error = -ETIMEDOUT;
3051c6a0718SPierre Ossman 	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
3061c6a0718SPierre Ossman 		/*
3071c6a0718SPierre Ossman 		 * workaround for erratum #42:
3081c6a0718SPierre Ossman 		 * Intel PXA27x Family Processor Specification Update Rev 001
30990e07d9fSNicolas Pitre 		 * A bogus CRC error can appear if the msb of a 136 bit
31090e07d9fSNicolas Pitre 		 * response is a one.
3111c6a0718SPierre Ossman 		 */
312e10a854cSCliff Brake 		if (cpu_is_pxa27x() &&
313e10a854cSCliff Brake 		    (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000))
3141c6a0718SPierre Ossman 			pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
315e10a854cSCliff Brake 		else
31617b0429dSPierre Ossman 			cmd->error = -EILSEQ;
3171c6a0718SPierre Ossman 	}
3181c6a0718SPierre Ossman 
3191c6a0718SPierre Ossman 	pxamci_disable_irq(host, END_CMD_RES);
32017b0429dSPierre Ossman 	if (host->data && !cmd->error) {
3211c6a0718SPierre Ossman 		pxamci_enable_irq(host, DATA_TRAN_DONE);
322b6018958SCliff Brake 		/*
323b6018958SCliff Brake 		 * workaround for erratum #91, if doing write
324b6018958SCliff Brake 		 * enable DMA late
325b6018958SCliff Brake 		 */
326b6018958SCliff Brake 		if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
3276464b714SDaniel Mack 			dma_async_issue_pending(host->dma_chan_tx);
3281c6a0718SPierre Ossman 	} else {
3291c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
3301c6a0718SPierre Ossman 	}
3311c6a0718SPierre Ossman 
3321c6a0718SPierre Ossman 	return 1;
3331c6a0718SPierre Ossman }
3341c6a0718SPierre Ossman 
3351c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
3361c6a0718SPierre Ossman {
3371c6a0718SPierre Ossman 	struct mmc_data *data = host->data;
3386464b714SDaniel Mack 	struct dma_chan *chan;
3391c6a0718SPierre Ossman 
3401c6a0718SPierre Ossman 	if (!data)
3411c6a0718SPierre Ossman 		return 0;
3421c6a0718SPierre Ossman 
3436464b714SDaniel Mack 	if (data->flags & MMC_DATA_READ)
3446464b714SDaniel Mack 		chan = host->dma_chan_rx;
3456464b714SDaniel Mack 	else
3466464b714SDaniel Mack 		chan = host->dma_chan_tx;
3476464b714SDaniel Mack 	dma_unmap_sg(chan->device->dev,
3486464b714SDaniel Mack 		     data->sg, data->sg_len, host->dma_dir);
3491c6a0718SPierre Ossman 
3501c6a0718SPierre Ossman 	if (stat & STAT_READ_TIME_OUT)
35117b0429dSPierre Ossman 		data->error = -ETIMEDOUT;
3521c6a0718SPierre Ossman 	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
35317b0429dSPierre Ossman 		data->error = -EILSEQ;
3541c6a0718SPierre Ossman 
3551c6a0718SPierre Ossman 	/*
3561c6a0718SPierre Ossman 	 * There appears to be a hardware design bug here.  There seems to
3571c6a0718SPierre Ossman 	 * be no way to find out how much data was transferred to the card.
3581c6a0718SPierre Ossman 	 * This means that if there was an error on any block, we mark all
3591c6a0718SPierre Ossman 	 * data blocks as being in error.
3601c6a0718SPierre Ossman 	 */
36117b0429dSPierre Ossman 	if (!data->error)
3621c6a0718SPierre Ossman 		data->bytes_xfered = data->blocks * data->blksz;
3631c6a0718SPierre Ossman 	else
3641c6a0718SPierre Ossman 		data->bytes_xfered = 0;
3651c6a0718SPierre Ossman 
3661c6a0718SPierre Ossman 	pxamci_disable_irq(host, DATA_TRAN_DONE);
3671c6a0718SPierre Ossman 
3681c6a0718SPierre Ossman 	host->data = NULL;
3691c6a0718SPierre Ossman 	if (host->mrq->stop) {
3701c6a0718SPierre Ossman 		pxamci_stop_clock(host);
371df456f47SBridge Wu 		pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
3721c6a0718SPierre Ossman 	} else {
3731c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
3741c6a0718SPierre Ossman 	}
3751c6a0718SPierre Ossman 
3761c6a0718SPierre Ossman 	return 1;
3771c6a0718SPierre Ossman }
3781c6a0718SPierre Ossman 
3791c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid)
3801c6a0718SPierre Ossman {
3811c6a0718SPierre Ossman 	struct pxamci_host *host = devid;
3821c6a0718SPierre Ossman 	unsigned int ireg;
3831c6a0718SPierre Ossman 	int handled = 0;
3841c6a0718SPierre Ossman 
38581ab570fSBridge Wu 	ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
3861c6a0718SPierre Ossman 
3871c6a0718SPierre Ossman 	if (ireg) {
3881c6a0718SPierre Ossman 		unsigned stat = readl(host->base + MMC_STAT);
3891c6a0718SPierre Ossman 
3901c6a0718SPierre Ossman 		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
3911c6a0718SPierre Ossman 
3921c6a0718SPierre Ossman 		if (ireg & END_CMD_RES)
3931c6a0718SPierre Ossman 			handled |= pxamci_cmd_done(host, stat);
3941c6a0718SPierre Ossman 		if (ireg & DATA_TRAN_DONE)
3951c6a0718SPierre Ossman 			handled |= pxamci_data_done(host, stat);
3965d3ad4e8SBridge Wu 		if (ireg & SDIO_INT) {
3975d3ad4e8SBridge Wu 			mmc_signal_sdio_irq(host->mmc);
3985d3ad4e8SBridge Wu 			handled = 1;
3995d3ad4e8SBridge Wu 		}
4001c6a0718SPierre Ossman 	}
4011c6a0718SPierre Ossman 
4021c6a0718SPierre Ossman 	return IRQ_RETVAL(handled);
4031c6a0718SPierre Ossman }
4041c6a0718SPierre Ossman 
4051c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
4061c6a0718SPierre Ossman {
4071c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
4081c6a0718SPierre Ossman 	unsigned int cmdat;
4091c6a0718SPierre Ossman 
4101c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
4111c6a0718SPierre Ossman 
4121c6a0718SPierre Ossman 	host->mrq = mrq;
4131c6a0718SPierre Ossman 
4141c6a0718SPierre Ossman 	pxamci_stop_clock(host);
4151c6a0718SPierre Ossman 
4161c6a0718SPierre Ossman 	cmdat = host->cmdat;
4171c6a0718SPierre Ossman 	host->cmdat &= ~CMDAT_INIT;
4181c6a0718SPierre Ossman 
4191c6a0718SPierre Ossman 	if (mrq->data) {
4201c6a0718SPierre Ossman 		pxamci_setup_data(host, mrq->data);
4211c6a0718SPierre Ossman 
4221c6a0718SPierre Ossman 		cmdat &= ~CMDAT_BUSY;
4231c6a0718SPierre Ossman 		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
4241c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_WRITE)
4251c6a0718SPierre Ossman 			cmdat |= CMDAT_WRITE;
4261c6a0718SPierre Ossman 	}
4271c6a0718SPierre Ossman 
4281c6a0718SPierre Ossman 	pxamci_start_cmd(host, mrq->cmd, cmdat);
4291c6a0718SPierre Ossman }
4301c6a0718SPierre Ossman 
4311c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc)
4321c6a0718SPierre Ossman {
4331c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
4341c6a0718SPierre Ossman 
435fd546ee6SRobert Jarzmik 	if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro))
436fd546ee6SRobert Jarzmik 		return mmc_gpio_get_ro(mmc);
4371c6a0718SPierre Ossman 	if (host->pdata && host->pdata->get_ro)
43808f80bb5SAnton Vorontsov 		return !!host->pdata->get_ro(mmc_dev(mmc));
43908f80bb5SAnton Vorontsov 	/*
44008f80bb5SAnton Vorontsov 	 * Board doesn't support read only detection; let the mmc core
44108f80bb5SAnton Vorontsov 	 * decide what to do.
44208f80bb5SAnton Vorontsov 	 */
44308f80bb5SAnton Vorontsov 	return -ENOSYS;
4441c6a0718SPierre Ossman }
4451c6a0718SPierre Ossman 
4461c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
4471c6a0718SPierre Ossman {
4481c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
4491c6a0718SPierre Ossman 
4501c6a0718SPierre Ossman 	if (ios->clock) {
451ebebd9b0SRussell King 		unsigned long rate = host->clkrate;
452ebebd9b0SRussell King 		unsigned int clk = rate / ios->clock;
453ebebd9b0SRussell King 
454d8cb70d1SRussell King 		if (host->clkrt == CLKRT_OFF)
455e7370819SRobert Jarzmik 			clk_prepare_enable(host->clk);
456d8cb70d1SRussell King 
45764eb036aSBridge Wu 		if (ios->clock == 26000000) {
458fa3f9938SHaojian Zhuang 			/* to support 26MHz */
45964eb036aSBridge Wu 			host->clkrt = 7;
46064eb036aSBridge Wu 		} else {
46164eb036aSBridge Wu 			/* to handle (19.5MHz, 26MHz) */
46264eb036aSBridge Wu 			if (!clk)
46364eb036aSBridge Wu 				clk = 1;
46464eb036aSBridge Wu 
465ebebd9b0SRussell King 			/*
466ebebd9b0SRussell King 			 * clk might result in a lower divisor than we
467ebebd9b0SRussell King 			 * desire.  check for that condition and adjust
468ebebd9b0SRussell King 			 * as appropriate.
469ebebd9b0SRussell King 			 */
470ebebd9b0SRussell King 			if (rate / clk > ios->clock)
4711c6a0718SPierre Ossman 				clk <<= 1;
4721c6a0718SPierre Ossman 			host->clkrt = fls(clk) - 1;
47364eb036aSBridge Wu 		}
4741c6a0718SPierre Ossman 
4751c6a0718SPierre Ossman 		/*
4761c6a0718SPierre Ossman 		 * we write clkrt on the next command
4771c6a0718SPierre Ossman 		 */
4781c6a0718SPierre Ossman 	} else {
4791c6a0718SPierre Ossman 		pxamci_stop_clock(host);
480d8cb70d1SRussell King 		if (host->clkrt != CLKRT_OFF) {
481d8cb70d1SRussell King 			host->clkrt = CLKRT_OFF;
482e7370819SRobert Jarzmik 			clk_disable_unprepare(host->clk);
4831c6a0718SPierre Ossman 		}
484d8cb70d1SRussell King 	}
4851c6a0718SPierre Ossman 
4861c6a0718SPierre Ossman 	if (host->power_mode != ios->power_mode) {
48799fc5131SLinus Walleij 		int ret;
48899fc5131SLinus Walleij 
4891c6a0718SPierre Ossman 		host->power_mode = ios->power_mode;
4901c6a0718SPierre Ossman 
49199fc5131SLinus Walleij 		ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
49299fc5131SLinus Walleij 		if (ret) {
49399fc5131SLinus Walleij 			dev_err(mmc_dev(mmc), "unable to set power\n");
49499fc5131SLinus Walleij 			/*
49599fc5131SLinus Walleij 			 * The .set_ios() function in the mmc_host_ops
49699fc5131SLinus Walleij 			 * struct return void, and failing to set the
49799fc5131SLinus Walleij 			 * power should be rare so we print an error and
49899fc5131SLinus Walleij 			 * return here.
49999fc5131SLinus Walleij 			 */
50099fc5131SLinus Walleij 			return;
50199fc5131SLinus Walleij 		}
5021c6a0718SPierre Ossman 
5031c6a0718SPierre Ossman 		if (ios->power_mode == MMC_POWER_ON)
5041c6a0718SPierre Ossman 			host->cmdat |= CMDAT_INIT;
5051c6a0718SPierre Ossman 	}
5061c6a0718SPierre Ossman 
507df456f47SBridge Wu 	if (ios->bus_width == MMC_BUS_WIDTH_4)
508df456f47SBridge Wu 		host->cmdat |= CMDAT_SD_4DAT;
509df456f47SBridge Wu 	else
510df456f47SBridge Wu 		host->cmdat &= ~CMDAT_SD_4DAT;
511df456f47SBridge Wu 
51299fc5131SLinus Walleij 	dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
5131c6a0718SPierre Ossman 		host->clkrt, host->cmdat);
5141c6a0718SPierre Ossman }
5151c6a0718SPierre Ossman 
5165d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
5175d3ad4e8SBridge Wu {
5185d3ad4e8SBridge Wu 	struct pxamci_host *pxa_host = mmc_priv(host);
5195d3ad4e8SBridge Wu 
5205d3ad4e8SBridge Wu 	if (enable)
5215d3ad4e8SBridge Wu 		pxamci_enable_irq(pxa_host, SDIO_INT);
5225d3ad4e8SBridge Wu 	else
5235d3ad4e8SBridge Wu 		pxamci_disable_irq(pxa_host, SDIO_INT);
5245d3ad4e8SBridge Wu }
5255d3ad4e8SBridge Wu 
5261c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = {
5271c6a0718SPierre Ossman 	.request		= pxamci_request,
528fd546ee6SRobert Jarzmik 	.get_cd			= mmc_gpio_get_cd,
5291c6a0718SPierre Ossman 	.get_ro			= pxamci_get_ro,
5301c6a0718SPierre Ossman 	.set_ios		= pxamci_set_ios,
5315d3ad4e8SBridge Wu 	.enable_sdio_irq	= pxamci_enable_sdio_irq,
5321c6a0718SPierre Ossman };
5331c6a0718SPierre Ossman 
5346464b714SDaniel Mack static void pxamci_dma_irq(void *param)
5351c6a0718SPierre Ossman {
5366464b714SDaniel Mack 	struct pxamci_host *host = param;
5376464b714SDaniel Mack 	struct dma_tx_state state;
5386464b714SDaniel Mack 	enum dma_status status;
5396464b714SDaniel Mack 	struct dma_chan *chan;
5406464b714SDaniel Mack 	unsigned long flags;
541c783837bSNicolas Pitre 
5426464b714SDaniel Mack 	spin_lock_irqsave(&host->lock, flags);
5436464b714SDaniel Mack 
5446464b714SDaniel Mack 	if (!host->data)
5456464b714SDaniel Mack 		goto out_unlock;
5466464b714SDaniel Mack 
5476464b714SDaniel Mack 	if (host->data->flags & MMC_DATA_READ)
5486464b714SDaniel Mack 		chan = host->dma_chan_rx;
5496464b714SDaniel Mack 	else
5506464b714SDaniel Mack 		chan = host->dma_chan_tx;
5516464b714SDaniel Mack 
5526464b714SDaniel Mack 	status = dmaengine_tx_status(chan, host->dma_cookie, &state);
5536464b714SDaniel Mack 
5546464b714SDaniel Mack 	if (likely(status == DMA_COMPLETE)) {
555c783837bSNicolas Pitre 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
556c783837bSNicolas Pitre 	} else {
5576464b714SDaniel Mack 		pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
5586464b714SDaniel Mack 			host->data->flags & MMC_DATA_READ ? "rx" : "tx");
559c783837bSNicolas Pitre 		host->data->error = -EIO;
560c783837bSNicolas Pitre 		pxamci_data_done(host, 0);
561c783837bSNicolas Pitre 	}
5626464b714SDaniel Mack 
5636464b714SDaniel Mack out_unlock:
5646464b714SDaniel Mack 	spin_unlock_irqrestore(&host->lock, flags);
5651c6a0718SPierre Ossman }
5661c6a0718SPierre Ossman 
5671c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid)
5681c6a0718SPierre Ossman {
5691c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(devid);
5701c6a0718SPierre Ossman 
57138a8dda9SDaniel Mack 	mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms));
5721c6a0718SPierre Ossman 	return IRQ_HANDLED;
5731c6a0718SPierre Ossman }
5741c6a0718SPierre Ossman 
575e6027b46SDaniel Mack #ifdef CONFIG_OF
576e6027b46SDaniel Mack static const struct of_device_id pxa_mmc_dt_ids[] = {
577e6027b46SDaniel Mack         { .compatible = "marvell,pxa-mmc" },
578e6027b46SDaniel Mack         { }
579e6027b46SDaniel Mack };
580e6027b46SDaniel Mack 
581e6027b46SDaniel Mack MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
582e6027b46SDaniel Mack 
583fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev,
584fa3a5115SDaniel Mack 			  struct mmc_host *mmc)
585e6027b46SDaniel Mack {
586e6027b46SDaniel Mack 	struct device_node *np = pdev->dev.of_node;
58738a8dda9SDaniel Mack 	struct pxamci_host *host = mmc_priv(mmc);
588e6027b46SDaniel Mack 	u32 tmp;
589fa3a5115SDaniel Mack 	int ret;
590e6027b46SDaniel Mack 
591e6027b46SDaniel Mack 	if (!np)
592e6027b46SDaniel Mack 		return 0;
593e6027b46SDaniel Mack 
594e6027b46SDaniel Mack 	/* pxa-mmc specific */
595e6027b46SDaniel Mack 	if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
59638a8dda9SDaniel Mack 		host->detect_delay_ms = tmp;
597e6027b46SDaniel Mack 
598fa3a5115SDaniel Mack 	ret = mmc_of_parse(mmc);
599fa3a5115SDaniel Mack 	if (ret < 0)
600fa3a5115SDaniel Mack 		return ret;
601fa3a5115SDaniel Mack 
602e6027b46SDaniel Mack 	return 0;
603e6027b46SDaniel Mack }
604e6027b46SDaniel Mack #else
605fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev,
606fa3a5115SDaniel Mack 			  struct mmc_host *mmc)
607e6027b46SDaniel Mack {
608e6027b46SDaniel Mack         return 0;
609e6027b46SDaniel Mack }
610e6027b46SDaniel Mack #endif
611e6027b46SDaniel Mack 
6121c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev)
6131c6a0718SPierre Ossman {
6141c6a0718SPierre Ossman 	struct mmc_host *mmc;
6151c6a0718SPierre Ossman 	struct pxamci_host *host = NULL;
6166b3348f9SRobert Jarzmik 	struct resource *r;
61738a8dda9SDaniel Mack 	int ret, irq;
6181c6a0718SPierre Ossman 
6191c6a0718SPierre Ossman 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6201c6a0718SPierre Ossman 	irq = platform_get_irq(pdev, 0);
62107e7716cSRobert Jarzmik 	if (irq < 0)
62207e7716cSRobert Jarzmik 		return irq;
6231c6a0718SPierre Ossman 
6241c6a0718SPierre Ossman 	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
6251c6a0718SPierre Ossman 	if (!mmc) {
6261c6a0718SPierre Ossman 		ret = -ENOMEM;
6271c6a0718SPierre Ossman 		goto out;
6281c6a0718SPierre Ossman 	}
6291c6a0718SPierre Ossman 
6301c6a0718SPierre Ossman 	mmc->ops = &pxamci_ops;
6311c6a0718SPierre Ossman 
6321c6a0718SPierre Ossman 	/*
6331c6a0718SPierre Ossman 	 * We can do SG-DMA, but we don't because we never know how much
6341c6a0718SPierre Ossman 	 * data we successfully wrote to the card.
6351c6a0718SPierre Ossman 	 */
636a36274e0SMartin K. Petersen 	mmc->max_segs = NR_SG;
6371c6a0718SPierre Ossman 
6381c6a0718SPierre Ossman 	/*
6391c6a0718SPierre Ossman 	 * Our hardware DMA can handle a maximum of one page per SG entry.
6401c6a0718SPierre Ossman 	 */
6411c6a0718SPierre Ossman 	mmc->max_seg_size = PAGE_SIZE;
6421c6a0718SPierre Ossman 
6431c6a0718SPierre Ossman 	/*
644fe2dc44eSNicolas Pitre 	 * Block length register is only 10 bits before PXA27x.
6451c6a0718SPierre Ossman 	 */
6460ffcbfd5SEric Miao 	mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048;
6471c6a0718SPierre Ossman 
6481c6a0718SPierre Ossman 	/*
6491c6a0718SPierre Ossman 	 * Block count register is 16 bits.
6501c6a0718SPierre Ossman 	 */
6511c6a0718SPierre Ossman 	mmc->max_blk_count = 65535;
6521c6a0718SPierre Ossman 
653fa3a5115SDaniel Mack 	ret = pxamci_of_init(pdev, mmc);
654fa3a5115SDaniel Mack 	if (ret)
655fa3a5115SDaniel Mack 		return ret;
656fa3a5115SDaniel Mack 
6571c6a0718SPierre Ossman 	host = mmc_priv(mmc);
6581c6a0718SPierre Ossman 	host->mmc = mmc;
6591c6a0718SPierre Ossman 	host->pdata = pdev->dev.platform_data;
660d8cb70d1SRussell King 	host->clkrt = CLKRT_OFF;
661ebebd9b0SRussell King 
66207e7716cSRobert Jarzmik 	host->clk = devm_clk_get(&pdev->dev, NULL);
663ebebd9b0SRussell King 	if (IS_ERR(host->clk)) {
664ebebd9b0SRussell King 		ret = PTR_ERR(host->clk);
665ebebd9b0SRussell King 		host->clk = NULL;
666ebebd9b0SRussell King 		goto out;
667ebebd9b0SRussell King 	}
668ebebd9b0SRussell King 
669ebebd9b0SRussell King 	host->clkrate = clk_get_rate(host->clk);
670ebebd9b0SRussell King 
671ebebd9b0SRussell King 	/*
672ebebd9b0SRussell King 	 * Calculate minimum clock rate, rounding up.
673ebebd9b0SRussell King 	 */
674ebebd9b0SRussell King 	mmc->f_min = (host->clkrate + 63) / 64;
675fa3f9938SHaojian Zhuang 	mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
676ebebd9b0SRussell King 
67761951fd6SDaniel Mack 	ret = pxamci_init_ocr(host);
67861951fd6SDaniel Mack 	if (ret < 0)
67961951fd6SDaniel Mack 		return ret;
6808385f9cbSDaniel Ribeiro 
681de3ee99bSLinus Walleij 	mmc->caps = 0;
6825d3ad4e8SBridge Wu 	host->cmdat = 0;
6830ffcbfd5SEric Miao 	if (!cpu_is_pxa25x()) {
6845d3ad4e8SBridge Wu 		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
6855d3ad4e8SBridge Wu 		host->cmdat |= CMDAT_SDIO_INT_EN;
686fa3f9938SHaojian Zhuang 		if (mmc_has_26MHz())
68764eb036aSBridge Wu 			mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
68864eb036aSBridge Wu 				     MMC_CAP_SD_HIGHSPEED;
6895d3ad4e8SBridge Wu 	}
6901c6a0718SPierre Ossman 
6911c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
6921c6a0718SPierre Ossman 	host->res = r;
6931c6a0718SPierre Ossman 	host->imask = MMC_I_MASK_ALL;
6941c6a0718SPierre Ossman 
69507e7716cSRobert Jarzmik 	host->base = devm_ioremap_resource(&pdev->dev, r);
69607e7716cSRobert Jarzmik 	if (IS_ERR(host->base)) {
69707e7716cSRobert Jarzmik 		ret = PTR_ERR(host->base);
6981c6a0718SPierre Ossman 		goto out;
6991c6a0718SPierre Ossman 	}
7001c6a0718SPierre Ossman 
7011c6a0718SPierre Ossman 	/*
7021c6a0718SPierre Ossman 	 * Ensure that the host controller is shut down, and setup
7031c6a0718SPierre Ossman 	 * with our defaults.
7041c6a0718SPierre Ossman 	 */
7051c6a0718SPierre Ossman 	pxamci_stop_clock(host);
7061c6a0718SPierre Ossman 	writel(0, host->base + MMC_SPI);
7071c6a0718SPierre Ossman 	writel(64, host->base + MMC_RESTO);
7081c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
7091c6a0718SPierre Ossman 
710d92eaf57SDaniel Mack 	ret = devm_request_irq(&pdev->dev, irq, pxamci_irq, 0,
71107e7716cSRobert Jarzmik 			       DRIVER_NAME, host);
7121c6a0718SPierre Ossman 	if (ret)
7131c6a0718SPierre Ossman 		goto out;
7141c6a0718SPierre Ossman 
7151c6a0718SPierre Ossman 	platform_set_drvdata(pdev, mmc);
7161c6a0718SPierre Ossman 
7176b3348f9SRobert Jarzmik 	host->dma_chan_rx = dma_request_slave_channel(&pdev->dev, "rx");
7186464b714SDaniel Mack 	if (host->dma_chan_rx == NULL) {
7196464b714SDaniel Mack 		dev_err(&pdev->dev, "unable to request rx dma channel\n");
7206464b714SDaniel Mack 		ret = -ENODEV;
7216464b714SDaniel Mack 		goto out;
7226464b714SDaniel Mack 	}
7236464b714SDaniel Mack 
7246b3348f9SRobert Jarzmik 	host->dma_chan_tx = dma_request_slave_channel(&pdev->dev, "tx");
7256464b714SDaniel Mack 	if (host->dma_chan_tx == NULL) {
7266464b714SDaniel Mack 		dev_err(&pdev->dev, "unable to request tx dma channel\n");
7276464b714SDaniel Mack 		ret = -ENODEV;
7286464b714SDaniel Mack 		goto out;
7296464b714SDaniel Mack 	}
7309a788c6bSBridge Wu 
731b405db6cSRobert Jarzmik 	if (host->pdata) {
73238a8dda9SDaniel Mack 		int gpio_cd = host->pdata->gpio_card_detect;
73338a8dda9SDaniel Mack 		int gpio_ro = host->pdata->gpio_card_ro;
73438a8dda9SDaniel Mack 		int gpio_power = host->pdata->gpio_power;
73538a8dda9SDaniel Mack 
73638a8dda9SDaniel Mack 		host->detect_delay_ms = host->pdata->detect_delay_ms;
73738a8dda9SDaniel Mack 
738b405db6cSRobert Jarzmik 		if (gpio_is_valid(gpio_power)) {
739fd546ee6SRobert Jarzmik 			ret = devm_gpio_request(&pdev->dev, gpio_power,
740fd546ee6SRobert Jarzmik 						"mmc card power");
741b405db6cSRobert Jarzmik 			if (ret) {
74238a8dda9SDaniel Mack 				dev_err(&pdev->dev,
74338a8dda9SDaniel Mack 					"Failed requesting gpio_power %d\n",
744fd546ee6SRobert Jarzmik 					gpio_power);
745b405db6cSRobert Jarzmik 				goto out;
746b405db6cSRobert Jarzmik 			}
747b405db6cSRobert Jarzmik 			gpio_direction_output(gpio_power,
748b405db6cSRobert Jarzmik 					      host->pdata->gpio_power_invert);
749b405db6cSRobert Jarzmik 		}
75038a8dda9SDaniel Mack 
751b3802db5SRobert Jarzmik 		if (gpio_is_valid(gpio_ro)) {
752fd546ee6SRobert Jarzmik 			ret = mmc_gpio_request_ro(mmc, gpio_ro);
753b405db6cSRobert Jarzmik 			if (ret) {
75438a8dda9SDaniel Mack 				dev_err(&pdev->dev,
75538a8dda9SDaniel Mack 					"Failed requesting gpio_ro %d\n",
756b3802db5SRobert Jarzmik 					gpio_ro);
757fd546ee6SRobert Jarzmik 				goto out;
758fd546ee6SRobert Jarzmik 			} else {
75941c89159SRobert Jarzmik 				mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
76026d49fe7SRobert Jarzmik 					0 : MMC_CAP2_RO_ACTIVE_HIGH;
761b405db6cSRobert Jarzmik 			}
762b3802db5SRobert Jarzmik 		}
763fd546ee6SRobert Jarzmik 
764fd546ee6SRobert Jarzmik 		if (gpio_is_valid(gpio_cd))
765fd546ee6SRobert Jarzmik 			ret = mmc_gpio_request_cd(mmc, gpio_cd, 0);
766b405db6cSRobert Jarzmik 		if (ret) {
76738a8dda9SDaniel Mack 			dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n",
76838a8dda9SDaniel Mack 				gpio_cd);
769fd546ee6SRobert Jarzmik 			goto out;
770b405db6cSRobert Jarzmik 		}
771b405db6cSRobert Jarzmik 
77238a8dda9SDaniel Mack 		if (host->pdata->init)
7731c6a0718SPierre Ossman 			host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
7741c6a0718SPierre Ossman 
775b405db6cSRobert Jarzmik 		if (gpio_is_valid(gpio_power) && host->pdata->setpower)
776b405db6cSRobert Jarzmik 			dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n");
777b405db6cSRobert Jarzmik 		if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
778b405db6cSRobert Jarzmik 			dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n");
77938a8dda9SDaniel Mack 	}
780b405db6cSRobert Jarzmik 
7811c6a0718SPierre Ossman 	mmc_add_host(mmc);
7821c6a0718SPierre Ossman 
7831c6a0718SPierre Ossman 	return 0;
7841c6a0718SPierre Ossman 
7851c6a0718SPierre Ossman out:
7861c6a0718SPierre Ossman 	if (host) {
7876464b714SDaniel Mack 		if (host->dma_chan_rx)
7886464b714SDaniel Mack 			dma_release_channel(host->dma_chan_rx);
7896464b714SDaniel Mack 		if (host->dma_chan_tx)
7906464b714SDaniel Mack 			dma_release_channel(host->dma_chan_tx);
7911c6a0718SPierre Ossman 	}
7921c6a0718SPierre Ossman 	if (mmc)
7931c6a0718SPierre Ossman 		mmc_free_host(mmc);
7941c6a0718SPierre Ossman 	return ret;
7951c6a0718SPierre Ossman }
7961c6a0718SPierre Ossman 
7971c6a0718SPierre Ossman static int pxamci_remove(struct platform_device *pdev)
7981c6a0718SPierre Ossman {
7991c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(pdev);
8001c6a0718SPierre Ossman 
8011c6a0718SPierre Ossman 	if (mmc) {
8021c6a0718SPierre Ossman 		struct pxamci_host *host = mmc_priv(mmc);
8031c6a0718SPierre Ossman 
8045d6b1edfSDaniel Mack 		mmc_remove_host(mmc);
8055d6b1edfSDaniel Mack 
8061c6a0718SPierre Ossman 		if (host->pdata && host->pdata->exit)
8071c6a0718SPierre Ossman 			host->pdata->exit(&pdev->dev, mmc);
8081c6a0718SPierre Ossman 
8091c6a0718SPierre Ossman 		pxamci_stop_clock(host);
8101c6a0718SPierre Ossman 		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
8111c6a0718SPierre Ossman 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
8121c6a0718SPierre Ossman 		       host->base + MMC_I_MASK);
8131c6a0718SPierre Ossman 
8146464b714SDaniel Mack 		dmaengine_terminate_all(host->dma_chan_rx);
8156464b714SDaniel Mack 		dmaengine_terminate_all(host->dma_chan_tx);
8166464b714SDaniel Mack 		dma_release_channel(host->dma_chan_rx);
8176464b714SDaniel Mack 		dma_release_channel(host->dma_chan_tx);
8181c6a0718SPierre Ossman 
8191c6a0718SPierre Ossman 		mmc_free_host(mmc);
8201c6a0718SPierre Ossman 	}
82152c09186SDaniel Mack 
8221c6a0718SPierre Ossman 	return 0;
8231c6a0718SPierre Ossman }
8241c6a0718SPierre Ossman 
8251c6a0718SPierre Ossman static struct platform_driver pxamci_driver = {
8261c6a0718SPierre Ossman 	.probe		= pxamci_probe,
8271c6a0718SPierre Ossman 	.remove		= pxamci_remove,
8281c6a0718SPierre Ossman 	.driver		= {
8291c6a0718SPierre Ossman 		.name	= DRIVER_NAME,
830e6027b46SDaniel Mack 		.of_match_table = of_match_ptr(pxa_mmc_dt_ids),
8311c6a0718SPierre Ossman 	},
8321c6a0718SPierre Ossman };
8331c6a0718SPierre Ossman 
834d1f81a64SAxel Lin module_platform_driver(pxamci_driver);
8351c6a0718SPierre Ossman 
8361c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
8371c6a0718SPierre Ossman MODULE_LICENSE("GPL");
838bc65c724SKay Sievers MODULE_ALIAS("platform:pxa2xx-mci");
839