xref: /openbmc/linux/drivers/mmc/host/pxamci.c (revision fac44eb8)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21c6a0718SPierre Ossman /*
370f10482SPierre Ossman  *  linux/drivers/mmc/host/pxa.c - PXA MMCI driver
41c6a0718SPierre Ossman  *
51c6a0718SPierre Ossman  *  Copyright (C) 2003 Russell King, All Rights Reserved.
61c6a0718SPierre Ossman  *
71c6a0718SPierre Ossman  *  This hardware is really sick:
81c6a0718SPierre Ossman  *   - No way to clear interrupts.
91c6a0718SPierre Ossman  *   - Have to turn off the clock whenever we touch the device.
101c6a0718SPierre Ossman  *   - Doesn't tell you how many data blocks were transferred.
111c6a0718SPierre Ossman  *  Yuck!
121c6a0718SPierre Ossman  *
131c6a0718SPierre Ossman  *	1 and 3 byte data transfers not supported
141c6a0718SPierre Ossman  *	max block length up to 1023
151c6a0718SPierre Ossman  */
161c6a0718SPierre Ossman #include <linux/module.h>
171c6a0718SPierre Ossman #include <linux/init.h>
181c6a0718SPierre Ossman #include <linux/ioport.h>
191c6a0718SPierre Ossman #include <linux/platform_device.h>
201c6a0718SPierre Ossman #include <linux/delay.h>
211c6a0718SPierre Ossman #include <linux/interrupt.h>
226464b714SDaniel Mack #include <linux/dmaengine.h>
231c6a0718SPierre Ossman #include <linux/dma-mapping.h>
24ebebd9b0SRussell King #include <linux/clk.h>
25ebebd9b0SRussell King #include <linux/err.h>
261c6a0718SPierre Ossman #include <linux/mmc/host.h>
27fd546ee6SRobert Jarzmik #include <linux/mmc/slot-gpio.h>
2805678a96SRussell King #include <linux/io.h>
298385f9cbSDaniel Ribeiro #include <linux/regulator/consumer.h>
30f54005b5SLinus Walleij #include <linux/gpio/consumer.h>
315a0e3ad6STejun Heo #include <linux/gfp.h>
32e6027b46SDaniel Mack #include <linux/of.h>
3308d3df8cSArnd Bergmann #include <linux/soc/pxa/cpu.h>
341c6a0718SPierre Ossman 
3587dfb311SMasahiro Yamada #include <linux/sizes.h>
361c6a0718SPierre Ossman 
37293b2da1SArnd Bergmann #include <linux/platform_data/mmc-pxamci.h>
381c6a0718SPierre Ossman 
391c6a0718SPierre Ossman #include "pxamci.h"
401c6a0718SPierre Ossman 
411c6a0718SPierre Ossman #define DRIVER_NAME	"pxa2xx-mci"
421c6a0718SPierre Ossman 
431c6a0718SPierre Ossman #define NR_SG	1
44d8cb70d1SRussell King #define CLKRT_OFF	(~0)
451c6a0718SPierre Ossman 
46fa3f9938SHaojian Zhuang #define mmc_has_26MHz()		(cpu_is_pxa300() || cpu_is_pxa310() \
47fa3f9938SHaojian Zhuang 				|| cpu_is_pxa935())
48fa3f9938SHaojian Zhuang 
491c6a0718SPierre Ossman struct pxamci_host {
501c6a0718SPierre Ossman 	struct mmc_host		*mmc;
511c6a0718SPierre Ossman 	spinlock_t		lock;
521c6a0718SPierre Ossman 	struct resource		*res;
531c6a0718SPierre Ossman 	void __iomem		*base;
54ebebd9b0SRussell King 	struct clk		*clk;
55ebebd9b0SRussell King 	unsigned long		clkrate;
561c6a0718SPierre Ossman 	unsigned int		clkrt;
571c6a0718SPierre Ossman 	unsigned int		cmdat;
581c6a0718SPierre Ossman 	unsigned int		imask;
591c6a0718SPierre Ossman 	unsigned int		power_mode;
6038a8dda9SDaniel Mack 	unsigned long		detect_delay_ms;
61c914a27cSLinus Walleij 	bool			use_ro_gpio;
62f54005b5SLinus Walleij 	struct gpio_desc	*power;
631c6a0718SPierre Ossman 	struct pxamci_platform_data *pdata;
641c6a0718SPierre Ossman 
651c6a0718SPierre Ossman 	struct mmc_request	*mrq;
661c6a0718SPierre Ossman 	struct mmc_command	*cmd;
671c6a0718SPierre Ossman 	struct mmc_data		*data;
681c6a0718SPierre Ossman 
696464b714SDaniel Mack 	struct dma_chan		*dma_chan_rx;
706464b714SDaniel Mack 	struct dma_chan		*dma_chan_tx;
716464b714SDaniel Mack 	dma_cookie_t		dma_cookie;
721c6a0718SPierre Ossman 	unsigned int		dma_len;
731c6a0718SPierre Ossman 	unsigned int		dma_dir;
741c6a0718SPierre Ossman };
751c6a0718SPierre Ossman 
pxamci_init_ocr(struct pxamci_host * host)7661951fd6SDaniel Mack static int pxamci_init_ocr(struct pxamci_host *host)
778385f9cbSDaniel Ribeiro {
7861951fd6SDaniel Mack 	struct mmc_host *mmc = host->mmc;
7961951fd6SDaniel Mack 	int ret;
808385f9cbSDaniel Ribeiro 
8161951fd6SDaniel Mack 	ret = mmc_regulator_get_supply(mmc);
8261951fd6SDaniel Mack 	if (ret < 0)
8361951fd6SDaniel Mack 		return ret;
8461951fd6SDaniel Mack 
8561951fd6SDaniel Mack 	if (IS_ERR(mmc->supply.vmmc)) {
868385f9cbSDaniel Ribeiro 		/* fall-back to platform data */
8761951fd6SDaniel Mack 		mmc->ocr_avail = host->pdata ?
888385f9cbSDaniel Ribeiro 			host->pdata->ocr_mask :
898385f9cbSDaniel Ribeiro 			MMC_VDD_32_33 | MMC_VDD_33_34;
908385f9cbSDaniel Ribeiro 	}
9161951fd6SDaniel Mack 
9261951fd6SDaniel Mack 	return 0;
938385f9cbSDaniel Ribeiro }
948385f9cbSDaniel Ribeiro 
pxamci_set_power(struct pxamci_host * host,unsigned char power_mode,unsigned int vdd)9599fc5131SLinus Walleij static inline int pxamci_set_power(struct pxamci_host *host,
9699fc5131SLinus Walleij 				    unsigned char power_mode,
9799fc5131SLinus Walleij 				    unsigned int vdd)
988385f9cbSDaniel Ribeiro {
9961951fd6SDaniel Mack 	struct mmc_host *mmc = host->mmc;
10061951fd6SDaniel Mack 	struct regulator *supply = mmc->supply.vmmc;
101b405db6cSRobert Jarzmik 
10261951fd6SDaniel Mack 	if (!IS_ERR(supply))
10361951fd6SDaniel Mack 		return mmc_regulator_set_ocr(mmc, supply, vdd);
10499fc5131SLinus Walleij 
105f54005b5SLinus Walleij 	if (host->power) {
106f54005b5SLinus Walleij 		bool on = !!((1 << vdd) & host->pdata->ocr_mask);
107f54005b5SLinus Walleij 		gpiod_set_value(host->power, on);
108b405db6cSRobert Jarzmik 	}
10961951fd6SDaniel Mack 
11061951fd6SDaniel Mack 	if (host->pdata && host->pdata->setpower)
111a829abf8SArnd Bergmann 		return host->pdata->setpower(mmc_dev(host->mmc), vdd);
11299fc5131SLinus Walleij 
11399fc5131SLinus Walleij 	return 0;
1148385f9cbSDaniel Ribeiro }
1158385f9cbSDaniel Ribeiro 
pxamci_stop_clock(struct pxamci_host * host)1161c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host)
1171c6a0718SPierre Ossman {
1181c6a0718SPierre Ossman 	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
1191c6a0718SPierre Ossman 		unsigned long timeout = 10000;
1201c6a0718SPierre Ossman 		unsigned int v;
1211c6a0718SPierre Ossman 
1221c6a0718SPierre Ossman 		writel(STOP_CLOCK, host->base + MMC_STRPCL);
1231c6a0718SPierre Ossman 
1241c6a0718SPierre Ossman 		do {
1251c6a0718SPierre Ossman 			v = readl(host->base + MMC_STAT);
1261c6a0718SPierre Ossman 			if (!(v & STAT_CLK_EN))
1271c6a0718SPierre Ossman 				break;
1281c6a0718SPierre Ossman 			udelay(1);
1291c6a0718SPierre Ossman 		} while (timeout--);
1301c6a0718SPierre Ossman 
1311c6a0718SPierre Ossman 		if (v & STAT_CLK_EN)
1321c6a0718SPierre Ossman 			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
1331c6a0718SPierre Ossman 	}
1341c6a0718SPierre Ossman }
1351c6a0718SPierre Ossman 
pxamci_enable_irq(struct pxamci_host * host,unsigned int mask)1361c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
1371c6a0718SPierre Ossman {
1381c6a0718SPierre Ossman 	unsigned long flags;
1391c6a0718SPierre Ossman 
1401c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
1411c6a0718SPierre Ossman 	host->imask &= ~mask;
1421c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1431c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1441c6a0718SPierre Ossman }
1451c6a0718SPierre Ossman 
pxamci_disable_irq(struct pxamci_host * host,unsigned int mask)1461c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
1471c6a0718SPierre Ossman {
1481c6a0718SPierre Ossman 	unsigned long flags;
1491c6a0718SPierre Ossman 
1501c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
1511c6a0718SPierre Ossman 	host->imask |= mask;
1521c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
1531c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
1541c6a0718SPierre Ossman }
1551c6a0718SPierre Ossman 
1566464b714SDaniel Mack static void pxamci_dma_irq(void *param);
1576464b714SDaniel Mack 
pxamci_setup_data(struct pxamci_host * host,struct mmc_data * data)1581c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
1591c6a0718SPierre Ossman {
1606464b714SDaniel Mack 	struct dma_async_tx_descriptor *tx;
161e60a582bSArnd Bergmann 	enum dma_transfer_direction direction;
1626464b714SDaniel Mack 	struct dma_slave_config	config;
1636464b714SDaniel Mack 	struct dma_chan *chan;
1641c6a0718SPierre Ossman 	unsigned int nob = data->blocks;
1651c6a0718SPierre Ossman 	unsigned long long clks;
1661c6a0718SPierre Ossman 	unsigned int timeout;
1676464b714SDaniel Mack 	int ret;
1681c6a0718SPierre Ossman 
1691c6a0718SPierre Ossman 	host->data = data;
1701c6a0718SPierre Ossman 
1711c6a0718SPierre Ossman 	writel(nob, host->base + MMC_NOB);
1721c6a0718SPierre Ossman 	writel(data->blksz, host->base + MMC_BLKLEN);
1731c6a0718SPierre Ossman 
174ebebd9b0SRussell King 	clks = (unsigned long long)data->timeout_ns * host->clkrate;
1751c6a0718SPierre Ossman 	do_div(clks, 1000000000UL);
1761c6a0718SPierre Ossman 	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
1771c6a0718SPierre Ossman 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
1781c6a0718SPierre Ossman 
1796464b714SDaniel Mack 	memset(&config, 0, sizeof(config));
1806464b714SDaniel Mack 	config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1816464b714SDaniel Mack 	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1826464b714SDaniel Mack 	config.src_addr = host->res->start + MMC_RXFIFO;
1836464b714SDaniel Mack 	config.dst_addr = host->res->start + MMC_TXFIFO;
1846464b714SDaniel Mack 	config.src_maxburst = 32;
1856464b714SDaniel Mack 	config.dst_maxburst = 32;
1866464b714SDaniel Mack 
1871c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ) {
1881c6a0718SPierre Ossman 		host->dma_dir = DMA_FROM_DEVICE;
1896464b714SDaniel Mack 		direction = DMA_DEV_TO_MEM;
1906464b714SDaniel Mack 		chan = host->dma_chan_rx;
1911c6a0718SPierre Ossman 	} else {
1921c6a0718SPierre Ossman 		host->dma_dir = DMA_TO_DEVICE;
1936464b714SDaniel Mack 		direction = DMA_MEM_TO_DEV;
1946464b714SDaniel Mack 		chan = host->dma_chan_tx;
1951c6a0718SPierre Ossman 	}
1961c6a0718SPierre Ossman 
1976464b714SDaniel Mack 	config.direction = direction;
1981c6a0718SPierre Ossman 
1996464b714SDaniel Mack 	ret = dmaengine_slave_config(chan, &config);
2006464b714SDaniel Mack 	if (ret < 0) {
2016464b714SDaniel Mack 		dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
2026464b714SDaniel Mack 		return;
2036464b714SDaniel Mack 	}
2046464b714SDaniel Mack 
2056464b714SDaniel Mack 	host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
2061c6a0718SPierre Ossman 				   host->dma_dir);
2071c6a0718SPierre Ossman 
2086464b714SDaniel Mack 	tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
2096464b714SDaniel Mack 				     DMA_PREP_INTERRUPT);
2106464b714SDaniel Mack 	if (!tx) {
2116464b714SDaniel Mack 		dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
2126464b714SDaniel Mack 		return;
2131c6a0718SPierre Ossman 	}
2141c6a0718SPierre Ossman 
2156464b714SDaniel Mack 	if (!(data->flags & MMC_DATA_READ)) {
2166464b714SDaniel Mack 		tx->callback = pxamci_dma_irq;
2176464b714SDaniel Mack 		tx->callback_param = host;
2186464b714SDaniel Mack 	}
2196464b714SDaniel Mack 
2206464b714SDaniel Mack 	host->dma_cookie = dmaengine_submit(tx);
221b6018958SCliff Brake 
222b6018958SCliff Brake 	/*
223b6018958SCliff Brake 	 * workaround for erratum #91:
224b6018958SCliff Brake 	 * only start DMA now if we are doing a read,
225b6018958SCliff Brake 	 * otherwise we wait until CMD/RESP has finished
226b6018958SCliff Brake 	 * before starting DMA.
227b6018958SCliff Brake 	 */
228b6018958SCliff Brake 	if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
2296464b714SDaniel Mack 		dma_async_issue_pending(chan);
2301c6a0718SPierre Ossman }
2311c6a0718SPierre Ossman 
pxamci_start_cmd(struct pxamci_host * host,struct mmc_command * cmd,unsigned int cmdat)2321c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
2331c6a0718SPierre Ossman {
2341c6a0718SPierre Ossman 	WARN_ON(host->cmd != NULL);
2351c6a0718SPierre Ossman 	host->cmd = cmd;
2361c6a0718SPierre Ossman 
2371c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_BUSY)
2381c6a0718SPierre Ossman 		cmdat |= CMDAT_BUSY;
2391c6a0718SPierre Ossman 
2401c6a0718SPierre Ossman #define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
2411c6a0718SPierre Ossman 	switch (RSP_TYPE(mmc_resp_type(cmd))) {
2421c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
2431c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_SHORT;
2441c6a0718SPierre Ossman 		break;
2451c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R3):
2461c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R3;
2471c6a0718SPierre Ossman 		break;
2481c6a0718SPierre Ossman 	case RSP_TYPE(MMC_RSP_R2):
2491c6a0718SPierre Ossman 		cmdat |= CMDAT_RESP_R2;
2501c6a0718SPierre Ossman 		break;
2511c6a0718SPierre Ossman 	default:
2521c6a0718SPierre Ossman 		break;
2531c6a0718SPierre Ossman 	}
2541c6a0718SPierre Ossman 
2551c6a0718SPierre Ossman 	writel(cmd->opcode, host->base + MMC_CMD);
2561c6a0718SPierre Ossman 	writel(cmd->arg >> 16, host->base + MMC_ARGH);
2571c6a0718SPierre Ossman 	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
2581c6a0718SPierre Ossman 	writel(cmdat, host->base + MMC_CMDAT);
2591c6a0718SPierre Ossman 	writel(host->clkrt, host->base + MMC_CLKRT);
2601c6a0718SPierre Ossman 
2611c6a0718SPierre Ossman 	writel(START_CLOCK, host->base + MMC_STRPCL);
2621c6a0718SPierre Ossman 
2631c6a0718SPierre Ossman 	pxamci_enable_irq(host, END_CMD_RES);
2641c6a0718SPierre Ossman }
2651c6a0718SPierre Ossman 
pxamci_finish_request(struct pxamci_host * host,struct mmc_request * mrq)2661c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
2671c6a0718SPierre Ossman {
2681c6a0718SPierre Ossman 	host->mrq = NULL;
2691c6a0718SPierre Ossman 	host->cmd = NULL;
2701c6a0718SPierre Ossman 	host->data = NULL;
2711c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
2721c6a0718SPierre Ossman }
2731c6a0718SPierre Ossman 
pxamci_cmd_done(struct pxamci_host * host,unsigned int stat)2741c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
2751c6a0718SPierre Ossman {
2761c6a0718SPierre Ossman 	struct mmc_command *cmd = host->cmd;
2771c6a0718SPierre Ossman 	int i;
2781c6a0718SPierre Ossman 	u32 v;
2791c6a0718SPierre Ossman 
2801c6a0718SPierre Ossman 	if (!cmd)
2811c6a0718SPierre Ossman 		return 0;
2821c6a0718SPierre Ossman 
2831c6a0718SPierre Ossman 	host->cmd = NULL;
2841c6a0718SPierre Ossman 
2851c6a0718SPierre Ossman 	/*
2861c6a0718SPierre Ossman 	 * Did I mention this is Sick.  We always need to
2871c6a0718SPierre Ossman 	 * discard the upper 8 bits of the first 16-bit word.
2881c6a0718SPierre Ossman 	 */
2891c6a0718SPierre Ossman 	v = readl(host->base + MMC_RES) & 0xffff;
2901c6a0718SPierre Ossman 	for (i = 0; i < 4; i++) {
2911c6a0718SPierre Ossman 		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
2921c6a0718SPierre Ossman 		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
2931c6a0718SPierre Ossman 		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
2941c6a0718SPierre Ossman 		v = w2;
2951c6a0718SPierre Ossman 	}
2961c6a0718SPierre Ossman 
2971c6a0718SPierre Ossman 	if (stat & STAT_TIME_OUT_RESPONSE) {
29817b0429dSPierre Ossman 		cmd->error = -ETIMEDOUT;
2991c6a0718SPierre Ossman 	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
3001c6a0718SPierre Ossman 		/*
3011c6a0718SPierre Ossman 		 * workaround for erratum #42:
3021c6a0718SPierre Ossman 		 * Intel PXA27x Family Processor Specification Update Rev 001
30390e07d9fSNicolas Pitre 		 * A bogus CRC error can appear if the msb of a 136 bit
30490e07d9fSNicolas Pitre 		 * response is a one.
3051c6a0718SPierre Ossman 		 */
306e10a854cSCliff Brake 		if (cpu_is_pxa27x() &&
307e10a854cSCliff Brake 		    (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000))
3081c6a0718SPierre Ossman 			pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
309e10a854cSCliff Brake 		else
31017b0429dSPierre Ossman 			cmd->error = -EILSEQ;
3111c6a0718SPierre Ossman 	}
3121c6a0718SPierre Ossman 
3131c6a0718SPierre Ossman 	pxamci_disable_irq(host, END_CMD_RES);
31417b0429dSPierre Ossman 	if (host->data && !cmd->error) {
3151c6a0718SPierre Ossman 		pxamci_enable_irq(host, DATA_TRAN_DONE);
316b6018958SCliff Brake 		/*
317b6018958SCliff Brake 		 * workaround for erratum #91, if doing write
318b6018958SCliff Brake 		 * enable DMA late
319b6018958SCliff Brake 		 */
320b6018958SCliff Brake 		if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
3216464b714SDaniel Mack 			dma_async_issue_pending(host->dma_chan_tx);
3221c6a0718SPierre Ossman 	} else {
3231c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
3241c6a0718SPierre Ossman 	}
3251c6a0718SPierre Ossman 
3261c6a0718SPierre Ossman 	return 1;
3271c6a0718SPierre Ossman }
3281c6a0718SPierre Ossman 
pxamci_data_done(struct pxamci_host * host,unsigned int stat)3291c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
3301c6a0718SPierre Ossman {
3311c6a0718SPierre Ossman 	struct mmc_data *data = host->data;
3326464b714SDaniel Mack 	struct dma_chan *chan;
3331c6a0718SPierre Ossman 
3341c6a0718SPierre Ossman 	if (!data)
3351c6a0718SPierre Ossman 		return 0;
3361c6a0718SPierre Ossman 
3376464b714SDaniel Mack 	if (data->flags & MMC_DATA_READ)
3386464b714SDaniel Mack 		chan = host->dma_chan_rx;
3396464b714SDaniel Mack 	else
3406464b714SDaniel Mack 		chan = host->dma_chan_tx;
3416464b714SDaniel Mack 	dma_unmap_sg(chan->device->dev,
3426464b714SDaniel Mack 		     data->sg, data->sg_len, host->dma_dir);
3431c6a0718SPierre Ossman 
3441c6a0718SPierre Ossman 	if (stat & STAT_READ_TIME_OUT)
34517b0429dSPierre Ossman 		data->error = -ETIMEDOUT;
3461c6a0718SPierre Ossman 	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
34717b0429dSPierre Ossman 		data->error = -EILSEQ;
3481c6a0718SPierre Ossman 
3491c6a0718SPierre Ossman 	/*
3501c6a0718SPierre Ossman 	 * There appears to be a hardware design bug here.  There seems to
3511c6a0718SPierre Ossman 	 * be no way to find out how much data was transferred to the card.
3521c6a0718SPierre Ossman 	 * This means that if there was an error on any block, we mark all
3531c6a0718SPierre Ossman 	 * data blocks as being in error.
3541c6a0718SPierre Ossman 	 */
35517b0429dSPierre Ossman 	if (!data->error)
3561c6a0718SPierre Ossman 		data->bytes_xfered = data->blocks * data->blksz;
3571c6a0718SPierre Ossman 	else
3581c6a0718SPierre Ossman 		data->bytes_xfered = 0;
3591c6a0718SPierre Ossman 
3601c6a0718SPierre Ossman 	pxamci_disable_irq(host, DATA_TRAN_DONE);
3611c6a0718SPierre Ossman 
3621c6a0718SPierre Ossman 	host->data = NULL;
3631c6a0718SPierre Ossman 	if (host->mrq->stop) {
3641c6a0718SPierre Ossman 		pxamci_stop_clock(host);
365df456f47SBridge Wu 		pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
3661c6a0718SPierre Ossman 	} else {
3671c6a0718SPierre Ossman 		pxamci_finish_request(host, host->mrq);
3681c6a0718SPierre Ossman 	}
3691c6a0718SPierre Ossman 
3701c6a0718SPierre Ossman 	return 1;
3711c6a0718SPierre Ossman }
3721c6a0718SPierre Ossman 
pxamci_irq(int irq,void * devid)3731c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid)
3741c6a0718SPierre Ossman {
3751c6a0718SPierre Ossman 	struct pxamci_host *host = devid;
3761c6a0718SPierre Ossman 	unsigned int ireg;
3771c6a0718SPierre Ossman 	int handled = 0;
3781c6a0718SPierre Ossman 
37981ab570fSBridge Wu 	ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
3801c6a0718SPierre Ossman 
3811c6a0718SPierre Ossman 	if (ireg) {
3821c6a0718SPierre Ossman 		unsigned stat = readl(host->base + MMC_STAT);
3831c6a0718SPierre Ossman 
3841c6a0718SPierre Ossman 		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
3851c6a0718SPierre Ossman 
3861c6a0718SPierre Ossman 		if (ireg & END_CMD_RES)
3871c6a0718SPierre Ossman 			handled |= pxamci_cmd_done(host, stat);
3881c6a0718SPierre Ossman 		if (ireg & DATA_TRAN_DONE)
3891c6a0718SPierre Ossman 			handled |= pxamci_data_done(host, stat);
3905d3ad4e8SBridge Wu 		if (ireg & SDIO_INT) {
3915d3ad4e8SBridge Wu 			mmc_signal_sdio_irq(host->mmc);
3925d3ad4e8SBridge Wu 			handled = 1;
3935d3ad4e8SBridge Wu 		}
3941c6a0718SPierre Ossman 	}
3951c6a0718SPierre Ossman 
3961c6a0718SPierre Ossman 	return IRQ_RETVAL(handled);
3971c6a0718SPierre Ossman }
3981c6a0718SPierre Ossman 
pxamci_request(struct mmc_host * mmc,struct mmc_request * mrq)3991c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
4001c6a0718SPierre Ossman {
4011c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
4021c6a0718SPierre Ossman 	unsigned int cmdat;
4031c6a0718SPierre Ossman 
4041c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
4051c6a0718SPierre Ossman 
4061c6a0718SPierre Ossman 	host->mrq = mrq;
4071c6a0718SPierre Ossman 
4081c6a0718SPierre Ossman 	pxamci_stop_clock(host);
4091c6a0718SPierre Ossman 
4101c6a0718SPierre Ossman 	cmdat = host->cmdat;
4111c6a0718SPierre Ossman 	host->cmdat &= ~CMDAT_INIT;
4121c6a0718SPierre Ossman 
4131c6a0718SPierre Ossman 	if (mrq->data) {
4141c6a0718SPierre Ossman 		pxamci_setup_data(host, mrq->data);
4151c6a0718SPierre Ossman 
4161c6a0718SPierre Ossman 		cmdat &= ~CMDAT_BUSY;
4171c6a0718SPierre Ossman 		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
4181c6a0718SPierre Ossman 		if (mrq->data->flags & MMC_DATA_WRITE)
4191c6a0718SPierre Ossman 			cmdat |= CMDAT_WRITE;
4201c6a0718SPierre Ossman 	}
4211c6a0718SPierre Ossman 
4221c6a0718SPierre Ossman 	pxamci_start_cmd(host, mrq->cmd, cmdat);
4231c6a0718SPierre Ossman }
4241c6a0718SPierre Ossman 
pxamci_get_ro(struct mmc_host * mmc)4251c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc)
4261c6a0718SPierre Ossman {
4271c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
4281c6a0718SPierre Ossman 
429c914a27cSLinus Walleij 	if (host->use_ro_gpio)
430fd546ee6SRobert Jarzmik 		return mmc_gpio_get_ro(mmc);
4311c6a0718SPierre Ossman 	if (host->pdata && host->pdata->get_ro)
43208f80bb5SAnton Vorontsov 		return !!host->pdata->get_ro(mmc_dev(mmc));
43308f80bb5SAnton Vorontsov 	/*
43408f80bb5SAnton Vorontsov 	 * Board doesn't support read only detection; let the mmc core
43508f80bb5SAnton Vorontsov 	 * decide what to do.
43608f80bb5SAnton Vorontsov 	 */
43708f80bb5SAnton Vorontsov 	return -ENOSYS;
4381c6a0718SPierre Ossman }
4391c6a0718SPierre Ossman 
pxamci_set_ios(struct mmc_host * mmc,struct mmc_ios * ios)4401c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
4411c6a0718SPierre Ossman {
4421c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(mmc);
4431c6a0718SPierre Ossman 
4441c6a0718SPierre Ossman 	if (ios->clock) {
445ebebd9b0SRussell King 		unsigned long rate = host->clkrate;
446ebebd9b0SRussell King 		unsigned int clk = rate / ios->clock;
447ebebd9b0SRussell King 
448d8cb70d1SRussell King 		if (host->clkrt == CLKRT_OFF)
449e7370819SRobert Jarzmik 			clk_prepare_enable(host->clk);
450d8cb70d1SRussell King 
45164eb036aSBridge Wu 		if (ios->clock == 26000000) {
452fa3f9938SHaojian Zhuang 			/* to support 26MHz */
45364eb036aSBridge Wu 			host->clkrt = 7;
45464eb036aSBridge Wu 		} else {
45564eb036aSBridge Wu 			/* to handle (19.5MHz, 26MHz) */
45664eb036aSBridge Wu 			if (!clk)
45764eb036aSBridge Wu 				clk = 1;
45864eb036aSBridge Wu 
459ebebd9b0SRussell King 			/*
460ebebd9b0SRussell King 			 * clk might result in a lower divisor than we
461ebebd9b0SRussell King 			 * desire.  check for that condition and adjust
462ebebd9b0SRussell King 			 * as appropriate.
463ebebd9b0SRussell King 			 */
464ebebd9b0SRussell King 			if (rate / clk > ios->clock)
4651c6a0718SPierre Ossman 				clk <<= 1;
4661c6a0718SPierre Ossman 			host->clkrt = fls(clk) - 1;
46764eb036aSBridge Wu 		}
4681c6a0718SPierre Ossman 
4691c6a0718SPierre Ossman 		/*
4701c6a0718SPierre Ossman 		 * we write clkrt on the next command
4711c6a0718SPierre Ossman 		 */
4721c6a0718SPierre Ossman 	} else {
4731c6a0718SPierre Ossman 		pxamci_stop_clock(host);
474d8cb70d1SRussell King 		if (host->clkrt != CLKRT_OFF) {
475d8cb70d1SRussell King 			host->clkrt = CLKRT_OFF;
476e7370819SRobert Jarzmik 			clk_disable_unprepare(host->clk);
4771c6a0718SPierre Ossman 		}
478d8cb70d1SRussell King 	}
4791c6a0718SPierre Ossman 
4801c6a0718SPierre Ossman 	if (host->power_mode != ios->power_mode) {
48199fc5131SLinus Walleij 		int ret;
48299fc5131SLinus Walleij 
4831c6a0718SPierre Ossman 		host->power_mode = ios->power_mode;
4841c6a0718SPierre Ossman 
48599fc5131SLinus Walleij 		ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
48699fc5131SLinus Walleij 		if (ret) {
48799fc5131SLinus Walleij 			dev_err(mmc_dev(mmc), "unable to set power\n");
48899fc5131SLinus Walleij 			/*
48999fc5131SLinus Walleij 			 * The .set_ios() function in the mmc_host_ops
49099fc5131SLinus Walleij 			 * struct return void, and failing to set the
49199fc5131SLinus Walleij 			 * power should be rare so we print an error and
49299fc5131SLinus Walleij 			 * return here.
49399fc5131SLinus Walleij 			 */
49499fc5131SLinus Walleij 			return;
49599fc5131SLinus Walleij 		}
4961c6a0718SPierre Ossman 
4971c6a0718SPierre Ossman 		if (ios->power_mode == MMC_POWER_ON)
4981c6a0718SPierre Ossman 			host->cmdat |= CMDAT_INIT;
4991c6a0718SPierre Ossman 	}
5001c6a0718SPierre Ossman 
501df456f47SBridge Wu 	if (ios->bus_width == MMC_BUS_WIDTH_4)
502df456f47SBridge Wu 		host->cmdat |= CMDAT_SD_4DAT;
503df456f47SBridge Wu 	else
504df456f47SBridge Wu 		host->cmdat &= ~CMDAT_SD_4DAT;
505df456f47SBridge Wu 
50699fc5131SLinus Walleij 	dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
5071c6a0718SPierre Ossman 		host->clkrt, host->cmdat);
5081c6a0718SPierre Ossman }
5091c6a0718SPierre Ossman 
pxamci_enable_sdio_irq(struct mmc_host * host,int enable)5105d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
5115d3ad4e8SBridge Wu {
5125d3ad4e8SBridge Wu 	struct pxamci_host *pxa_host = mmc_priv(host);
5135d3ad4e8SBridge Wu 
5145d3ad4e8SBridge Wu 	if (enable)
5155d3ad4e8SBridge Wu 		pxamci_enable_irq(pxa_host, SDIO_INT);
5165d3ad4e8SBridge Wu 	else
5175d3ad4e8SBridge Wu 		pxamci_disable_irq(pxa_host, SDIO_INT);
5185d3ad4e8SBridge Wu }
5195d3ad4e8SBridge Wu 
5201c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = {
5211c6a0718SPierre Ossman 	.request		= pxamci_request,
522fd546ee6SRobert Jarzmik 	.get_cd			= mmc_gpio_get_cd,
5231c6a0718SPierre Ossman 	.get_ro			= pxamci_get_ro,
5241c6a0718SPierre Ossman 	.set_ios		= pxamci_set_ios,
5255d3ad4e8SBridge Wu 	.enable_sdio_irq	= pxamci_enable_sdio_irq,
5261c6a0718SPierre Ossman };
5271c6a0718SPierre Ossman 
pxamci_dma_irq(void * param)5286464b714SDaniel Mack static void pxamci_dma_irq(void *param)
5291c6a0718SPierre Ossman {
5306464b714SDaniel Mack 	struct pxamci_host *host = param;
5316464b714SDaniel Mack 	struct dma_tx_state state;
5326464b714SDaniel Mack 	enum dma_status status;
5336464b714SDaniel Mack 	struct dma_chan *chan;
5346464b714SDaniel Mack 	unsigned long flags;
535c783837bSNicolas Pitre 
5366464b714SDaniel Mack 	spin_lock_irqsave(&host->lock, flags);
5376464b714SDaniel Mack 
5386464b714SDaniel Mack 	if (!host->data)
5396464b714SDaniel Mack 		goto out_unlock;
5406464b714SDaniel Mack 
5416464b714SDaniel Mack 	if (host->data->flags & MMC_DATA_READ)
5426464b714SDaniel Mack 		chan = host->dma_chan_rx;
5436464b714SDaniel Mack 	else
5446464b714SDaniel Mack 		chan = host->dma_chan_tx;
5456464b714SDaniel Mack 
5466464b714SDaniel Mack 	status = dmaengine_tx_status(chan, host->dma_cookie, &state);
5476464b714SDaniel Mack 
5486464b714SDaniel Mack 	if (likely(status == DMA_COMPLETE)) {
549c783837bSNicolas Pitre 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
550c783837bSNicolas Pitre 	} else {
5516464b714SDaniel Mack 		pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
5526464b714SDaniel Mack 			host->data->flags & MMC_DATA_READ ? "rx" : "tx");
553c783837bSNicolas Pitre 		host->data->error = -EIO;
554c783837bSNicolas Pitre 		pxamci_data_done(host, 0);
555c783837bSNicolas Pitre 	}
5566464b714SDaniel Mack 
5576464b714SDaniel Mack out_unlock:
5586464b714SDaniel Mack 	spin_unlock_irqrestore(&host->lock, flags);
5591c6a0718SPierre Ossman }
5601c6a0718SPierre Ossman 
pxamci_detect_irq(int irq,void * devid)5611c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid)
5621c6a0718SPierre Ossman {
5631c6a0718SPierre Ossman 	struct pxamci_host *host = mmc_priv(devid);
5641c6a0718SPierre Ossman 
56538a8dda9SDaniel Mack 	mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms));
5661c6a0718SPierre Ossman 	return IRQ_HANDLED;
5671c6a0718SPierre Ossman }
5681c6a0718SPierre Ossman 
569e6027b46SDaniel Mack #ifdef CONFIG_OF
570e6027b46SDaniel Mack static const struct of_device_id pxa_mmc_dt_ids[] = {
571e6027b46SDaniel Mack         { .compatible = "marvell,pxa-mmc" },
572e6027b46SDaniel Mack         { }
573e6027b46SDaniel Mack };
574e6027b46SDaniel Mack 
575e6027b46SDaniel Mack MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
576e6027b46SDaniel Mack 
pxamci_of_init(struct platform_device * pdev,struct mmc_host * mmc)577fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev,
578fa3a5115SDaniel Mack 			  struct mmc_host *mmc)
579e6027b46SDaniel Mack {
580e6027b46SDaniel Mack 	struct device_node *np = pdev->dev.of_node;
58138a8dda9SDaniel Mack 	struct pxamci_host *host = mmc_priv(mmc);
582e6027b46SDaniel Mack 	u32 tmp;
583fa3a5115SDaniel Mack 	int ret;
584e6027b46SDaniel Mack 
585e6027b46SDaniel Mack 	if (!np)
586e6027b46SDaniel Mack 		return 0;
587e6027b46SDaniel Mack 
588e6027b46SDaniel Mack 	/* pxa-mmc specific */
589e6027b46SDaniel Mack 	if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
59038a8dda9SDaniel Mack 		host->detect_delay_ms = tmp;
591e6027b46SDaniel Mack 
592fa3a5115SDaniel Mack 	ret = mmc_of_parse(mmc);
593fa3a5115SDaniel Mack 	if (ret < 0)
594fa3a5115SDaniel Mack 		return ret;
595fa3a5115SDaniel Mack 
596e6027b46SDaniel Mack 	return 0;
597e6027b46SDaniel Mack }
598e6027b46SDaniel Mack #else
pxamci_of_init(struct platform_device * pdev,struct mmc_host * mmc)599fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev,
600fa3a5115SDaniel Mack 			  struct mmc_host *mmc)
601e6027b46SDaniel Mack {
602e6027b46SDaniel Mack         return 0;
603e6027b46SDaniel Mack }
604e6027b46SDaniel Mack #endif
605e6027b46SDaniel Mack 
pxamci_probe(struct platform_device * pdev)6061c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev)
6071c6a0718SPierre Ossman {
6081c6a0718SPierre Ossman 	struct mmc_host *mmc;
6091c6a0718SPierre Ossman 	struct pxamci_host *host = NULL;
61023f3ff72SDaniel Mack 	struct device *dev = &pdev->dev;
6116b3348f9SRobert Jarzmik 	struct resource *r;
61238a8dda9SDaniel Mack 	int ret, irq;
6131c6a0718SPierre Ossman 
6141c6a0718SPierre Ossman 	irq = platform_get_irq(pdev, 0);
61507e7716cSRobert Jarzmik 	if (irq < 0)
61607e7716cSRobert Jarzmik 		return irq;
6171c6a0718SPierre Ossman 
61823f3ff72SDaniel Mack 	mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev);
6191c6a0718SPierre Ossman 	if (!mmc) {
6201c6a0718SPierre Ossman 		ret = -ENOMEM;
6211c6a0718SPierre Ossman 		goto out;
6221c6a0718SPierre Ossman 	}
6231c6a0718SPierre Ossman 
6241c6a0718SPierre Ossman 	mmc->ops = &pxamci_ops;
6251c6a0718SPierre Ossman 
6261c6a0718SPierre Ossman 	/*
6271c6a0718SPierre Ossman 	 * We can do SG-DMA, but we don't because we never know how much
6281c6a0718SPierre Ossman 	 * data we successfully wrote to the card.
6291c6a0718SPierre Ossman 	 */
630a36274e0SMartin K. Petersen 	mmc->max_segs = NR_SG;
6311c6a0718SPierre Ossman 
6321c6a0718SPierre Ossman 	/*
6331c6a0718SPierre Ossman 	 * Our hardware DMA can handle a maximum of one page per SG entry.
6341c6a0718SPierre Ossman 	 */
6351c6a0718SPierre Ossman 	mmc->max_seg_size = PAGE_SIZE;
6361c6a0718SPierre Ossman 
6371c6a0718SPierre Ossman 	/*
638fe2dc44eSNicolas Pitre 	 * Block length register is only 10 bits before PXA27x.
6391c6a0718SPierre Ossman 	 */
6400ffcbfd5SEric Miao 	mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048;
6411c6a0718SPierre Ossman 
6421c6a0718SPierre Ossman 	/*
6431c6a0718SPierre Ossman 	 * Block count register is 16 bits.
6441c6a0718SPierre Ossman 	 */
6451c6a0718SPierre Ossman 	mmc->max_blk_count = 65535;
6461c6a0718SPierre Ossman 
647fa3a5115SDaniel Mack 	ret = pxamci_of_init(pdev, mmc);
648fa3a5115SDaniel Mack 	if (ret)
64998d7c5e5SChristophe JAILLET 		goto out;
650fa3a5115SDaniel Mack 
6511c6a0718SPierre Ossman 	host = mmc_priv(mmc);
6521c6a0718SPierre Ossman 	host->mmc = mmc;
6531c6a0718SPierre Ossman 	host->pdata = pdev->dev.platform_data;
654d8cb70d1SRussell King 	host->clkrt = CLKRT_OFF;
655ebebd9b0SRussell King 
65623f3ff72SDaniel Mack 	host->clk = devm_clk_get(dev, NULL);
657ebebd9b0SRussell King 	if (IS_ERR(host->clk)) {
658ebebd9b0SRussell King 		ret = PTR_ERR(host->clk);
659ebebd9b0SRussell King 		host->clk = NULL;
660ebebd9b0SRussell King 		goto out;
661ebebd9b0SRussell King 	}
662ebebd9b0SRussell King 
663ebebd9b0SRussell King 	host->clkrate = clk_get_rate(host->clk);
664ebebd9b0SRussell King 
665ebebd9b0SRussell King 	/*
666ebebd9b0SRussell King 	 * Calculate minimum clock rate, rounding up.
667ebebd9b0SRussell King 	 */
668ebebd9b0SRussell King 	mmc->f_min = (host->clkrate + 63) / 64;
669fa3f9938SHaojian Zhuang 	mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
670ebebd9b0SRussell King 
67161951fd6SDaniel Mack 	ret = pxamci_init_ocr(host);
67261951fd6SDaniel Mack 	if (ret < 0)
673b886f54cSChristophe JAILLET 		goto out;
6748385f9cbSDaniel Ribeiro 
675de3ee99bSLinus Walleij 	mmc->caps = 0;
6765d3ad4e8SBridge Wu 	host->cmdat = 0;
6770ffcbfd5SEric Miao 	if (!cpu_is_pxa25x()) {
6785d3ad4e8SBridge Wu 		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
6795d3ad4e8SBridge Wu 		host->cmdat |= CMDAT_SDIO_INT_EN;
680fa3f9938SHaojian Zhuang 		if (mmc_has_26MHz())
68164eb036aSBridge Wu 			mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
68264eb036aSBridge Wu 				     MMC_CAP_SD_HIGHSPEED;
6835d3ad4e8SBridge Wu 	}
6841c6a0718SPierre Ossman 
6851c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
6861c6a0718SPierre Ossman 	host->imask = MMC_I_MASK_ALL;
6871c6a0718SPierre Ossman 
688c89a869bSYangtao Li 	host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
68907e7716cSRobert Jarzmik 	if (IS_ERR(host->base)) {
69007e7716cSRobert Jarzmik 		ret = PTR_ERR(host->base);
6911c6a0718SPierre Ossman 		goto out;
6921c6a0718SPierre Ossman 	}
693c89a869bSYangtao Li 	host->res = r;
6941c6a0718SPierre Ossman 
6951c6a0718SPierre Ossman 	/*
6961c6a0718SPierre Ossman 	 * Ensure that the host controller is shut down, and setup
6971c6a0718SPierre Ossman 	 * with our defaults.
6981c6a0718SPierre Ossman 	 */
6991c6a0718SPierre Ossman 	pxamci_stop_clock(host);
7001c6a0718SPierre Ossman 	writel(0, host->base + MMC_SPI);
7011c6a0718SPierre Ossman 	writel(64, host->base + MMC_RESTO);
7021c6a0718SPierre Ossman 	writel(host->imask, host->base + MMC_I_MASK);
7031c6a0718SPierre Ossman 
70423f3ff72SDaniel Mack 	ret = devm_request_irq(dev, irq, pxamci_irq, 0,
70507e7716cSRobert Jarzmik 			       DRIVER_NAME, host);
7061c6a0718SPierre Ossman 	if (ret)
7071c6a0718SPierre Ossman 		goto out;
7081c6a0718SPierre Ossman 
7091c6a0718SPierre Ossman 	platform_set_drvdata(pdev, mmc);
7101c6a0718SPierre Ossman 
711e1ebb456SPeter Ujfalusi 	host->dma_chan_rx = dma_request_chan(dev, "rx");
712e1ebb456SPeter Ujfalusi 	if (IS_ERR(host->dma_chan_rx)) {
71323f3ff72SDaniel Mack 		dev_err(dev, "unable to request rx dma channel\n");
714e1ebb456SPeter Ujfalusi 		ret = PTR_ERR(host->dma_chan_rx);
715e1ebb456SPeter Ujfalusi 		host->dma_chan_rx = NULL;
7166464b714SDaniel Mack 		goto out;
7176464b714SDaniel Mack 	}
7186464b714SDaniel Mack 
719e1ebb456SPeter Ujfalusi 	host->dma_chan_tx = dma_request_chan(dev, "tx");
720e1ebb456SPeter Ujfalusi 	if (IS_ERR(host->dma_chan_tx)) {
72123f3ff72SDaniel Mack 		dev_err(dev, "unable to request tx dma channel\n");
722e1ebb456SPeter Ujfalusi 		ret = PTR_ERR(host->dma_chan_tx);
723e1ebb456SPeter Ujfalusi 		host->dma_chan_tx = NULL;
7246464b714SDaniel Mack 		goto out;
7256464b714SDaniel Mack 	}
7269a788c6bSBridge Wu 
727b405db6cSRobert Jarzmik 	if (host->pdata) {
72838a8dda9SDaniel Mack 		host->detect_delay_ms = host->pdata->detect_delay_ms;
72938a8dda9SDaniel Mack 
730f54005b5SLinus Walleij 		host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
731f54005b5SLinus Walleij 		if (IS_ERR(host->power)) {
732d7b819b5SZhihao Cheng 			ret = PTR_ERR(host->power);
733f54005b5SLinus Walleij 			dev_err(dev, "Failed requesting gpio_power\n");
734b405db6cSRobert Jarzmik 			goto out;
735b405db6cSRobert Jarzmik 		}
73638a8dda9SDaniel Mack 
737c914a27cSLinus Walleij 		/* FIXME: should we pass detection delay to debounce? */
738d0052ad9SMichał Mirosław 		ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0);
739c914a27cSLinus Walleij 		if (ret && ret != -ENOENT) {
740c914a27cSLinus Walleij 			dev_err(dev, "Failed requesting gpio_cd\n");
741c914a27cSLinus Walleij 			goto out;
742c914a27cSLinus Walleij 		}
743c914a27cSLinus Walleij 
7449073d10bSMichał Mirosław 		if (!host->pdata->gpio_card_ro_invert)
7459073d10bSMichał Mirosław 			mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
7469073d10bSMichał Mirosław 
747d0052ad9SMichał Mirosław 		ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0);
748c914a27cSLinus Walleij 		if (ret && ret != -ENOENT) {
749c914a27cSLinus Walleij 			dev_err(dev, "Failed requesting gpio_ro\n");
750c914a27cSLinus Walleij 			goto out;
751c914a27cSLinus Walleij 		}
7529073d10bSMichał Mirosław 		if (!ret)
753c914a27cSLinus Walleij 			host->use_ro_gpio = true;
754b405db6cSRobert Jarzmik 
75538a8dda9SDaniel Mack 		if (host->pdata->init)
75623f3ff72SDaniel Mack 			host->pdata->init(dev, pxamci_detect_irq, mmc);
7571c6a0718SPierre Ossman 
758f54005b5SLinus Walleij 		if (host->power && host->pdata->setpower)
75923f3ff72SDaniel Mack 			dev_warn(dev, "gpio_power and setpower() both defined\n");
760c914a27cSLinus Walleij 		if (host->use_ro_gpio && host->pdata->get_ro)
76123f3ff72SDaniel Mack 			dev_warn(dev, "gpio_ro and get_ro() both defined\n");
76238a8dda9SDaniel Mack 	}
763b405db6cSRobert Jarzmik 
76480e1ef3aSYang Yingliang 	ret = mmc_add_host(mmc);
76580e1ef3aSYang Yingliang 	if (ret) {
76680e1ef3aSYang Yingliang 		if (host->pdata && host->pdata->exit)
76780e1ef3aSYang Yingliang 			host->pdata->exit(dev, mmc);
76880e1ef3aSYang Yingliang 		goto out;
76980e1ef3aSYang Yingliang 	}
7701c6a0718SPierre Ossman 
7711c6a0718SPierre Ossman 	return 0;
7721c6a0718SPierre Ossman 
7731c6a0718SPierre Ossman out:
7741c6a0718SPierre Ossman 	if (host) {
7756464b714SDaniel Mack 		if (host->dma_chan_rx)
7766464b714SDaniel Mack 			dma_release_channel(host->dma_chan_rx);
7776464b714SDaniel Mack 		if (host->dma_chan_tx)
7786464b714SDaniel Mack 			dma_release_channel(host->dma_chan_tx);
7791c6a0718SPierre Ossman 	}
7801c6a0718SPierre Ossman 	if (mmc)
7811c6a0718SPierre Ossman 		mmc_free_host(mmc);
7821c6a0718SPierre Ossman 	return ret;
7831c6a0718SPierre Ossman }
7841c6a0718SPierre Ossman 
pxamci_remove(struct platform_device * pdev)785*fac44eb8SYangtao Li static void pxamci_remove(struct platform_device *pdev)
7861c6a0718SPierre Ossman {
7871c6a0718SPierre Ossman 	struct mmc_host *mmc = platform_get_drvdata(pdev);
7881c6a0718SPierre Ossman 
7891c6a0718SPierre Ossman 	if (mmc) {
7901c6a0718SPierre Ossman 		struct pxamci_host *host = mmc_priv(mmc);
7911c6a0718SPierre Ossman 
7925d6b1edfSDaniel Mack 		mmc_remove_host(mmc);
7935d6b1edfSDaniel Mack 
7941c6a0718SPierre Ossman 		if (host->pdata && host->pdata->exit)
7951c6a0718SPierre Ossman 			host->pdata->exit(&pdev->dev, mmc);
7961c6a0718SPierre Ossman 
7971c6a0718SPierre Ossman 		pxamci_stop_clock(host);
7981c6a0718SPierre Ossman 		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
7991c6a0718SPierre Ossman 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
8001c6a0718SPierre Ossman 		       host->base + MMC_I_MASK);
8011c6a0718SPierre Ossman 
8026464b714SDaniel Mack 		dmaengine_terminate_all(host->dma_chan_rx);
8036464b714SDaniel Mack 		dmaengine_terminate_all(host->dma_chan_tx);
8046464b714SDaniel Mack 		dma_release_channel(host->dma_chan_rx);
8056464b714SDaniel Mack 		dma_release_channel(host->dma_chan_tx);
8061c6a0718SPierre Ossman 
8071c6a0718SPierre Ossman 		mmc_free_host(mmc);
8081c6a0718SPierre Ossman 	}
8091c6a0718SPierre Ossman }
8101c6a0718SPierre Ossman 
8111c6a0718SPierre Ossman static struct platform_driver pxamci_driver = {
8121c6a0718SPierre Ossman 	.probe		= pxamci_probe,
813*fac44eb8SYangtao Li 	.remove_new	= pxamci_remove,
8141c6a0718SPierre Ossman 	.driver		= {
8151c6a0718SPierre Ossman 		.name	= DRIVER_NAME,
81621b2cec6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
817e6027b46SDaniel Mack 		.of_match_table = of_match_ptr(pxa_mmc_dt_ids),
8181c6a0718SPierre Ossman 	},
8191c6a0718SPierre Ossman };
8201c6a0718SPierre Ossman 
821d1f81a64SAxel Lin module_platform_driver(pxamci_driver);
8221c6a0718SPierre Ossman 
8231c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
8241c6a0718SPierre Ossman MODULE_LICENSE("GPL");
825bc65c724SKay Sievers MODULE_ALIAS("platform:pxa2xx-mci");
826