[go: nahoru, domu]

161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen/*
261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  JZ4740 SD/MMC controller driver
461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *
561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  This program is free software; you can redistribute  it and/or modify it
661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  under  the terms of  the GNU General  Public License as published by the
761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  Free Software Foundation;  either version 2 of the  License, or (at your
861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  option) any later version.
961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *
1061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  You should have received a copy of the  GNU General Public License along
1161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  with this program; if not, write  to the Free Software Foundation, Inc.,
1261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *  675 Mass Ave, Cambridge, MA 02139, USA.
1361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *
1461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen */
1561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
1661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/mmc/host.h>
1758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen#include <linux/mmc/slot-gpio.h>
183119cbda858fc9ae10a69919e5f278abd6d93bb5Jamie Iles#include <linux/err.h>
1961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/io.h>
2061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/irq.h>
2161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/interrupt.h>
2261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/module.h>
2361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/platform_device.h>
2461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/delay.h>
2561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/scatterlist.h>
2661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/clk.h>
2761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
2861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/bitops.h>
2961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/gpio.h>
3061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <asm/mach-jz4740/gpio.h>
3161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <asm/cacheflush.h>
3261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/dma-mapping.h>
337ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli#include <linux/dmaengine.h>
3461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
357ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli#include <asm/mach-jz4740/dma.h>
3661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <asm/mach-jz4740/jz4740_mmc.h>
3761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
3861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_STRPCL	0x00
3961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_STATUS	0x04
4061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_CLKRT	0x08
4161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_CMDAT	0x0C
4261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RESTO	0x10
4361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RDTO		0x14
4461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_BLKLEN	0x18
4561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_NOB		0x1C
4661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_SNOB		0x20
4761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_IMASK	0x24
4861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_IREG		0x28
4961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_CMD		0x2C
5061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_ARG		0x30
5161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RESP_FIFO	0x34
5261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RXFIFO	0x38
5361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_TXFIFO	0x3C
5461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
5561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7)
5661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6)
5761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_START_READWAIT BIT(5)
5861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_STOP_READWAIT BIT(4)
5961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_RESET BIT(3)
6061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_START_OP BIT(2)
6161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0))
6261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_CLOCK_STOP BIT(0)
6361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_CLOCK_START BIT(1)
6461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
6561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
6661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_IS_RESETTING BIT(15)
6761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14)
6861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_PRG_DONE BIT(13)
6961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12)
7061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_END_CMD_RES BIT(11)
7161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10)
7261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_IS_READWAIT BIT(9)
7361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CLK_EN BIT(8)
7461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7)
7561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6)
7661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CRC_RES_ERR BIT(5)
7761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4)
7861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3)
7961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2)
8061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_TIMEOUT_RES BIT(1)
8161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_TIMEOUT_READ BIT(0)
8261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
8361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0))
8461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2))
8561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
8661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
8761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_IO_ABORT BIT(11)
8861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10)
8961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_DMA_EN BIT(8)
9061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_INIT BIT(7)
9161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_BUSY BIT(6)
9261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_STREAM BIT(5)
9361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_WRITE BIT(4)
9461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_DATA_EN BIT(3)
9561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0))
9661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RSP_R1 1
9761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RSP_R2 2
9861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RSP_R3 3
9961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
10061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_SDIO BIT(7)
10161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6)
10261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5)
10361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_END_CMD_RES BIT(2)
10461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_PRG_DONE BIT(1)
10561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0)
10661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
10761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
10861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CLK_RATE 24000000
10961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
11061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenenum jz4740_mmc_state {
11161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ4740_MMC_STATE_READ_RESPONSE,
11261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ4740_MMC_STATE_TRANSFER_DATA,
11361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ4740_MMC_STATE_SEND_STOP,
11461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ4740_MMC_STATE_DONE,
11561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen};
11661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
117bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistruct jz4740_mmc_host_next {
118bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	int sg_len;
119bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	s32 cookie;
120bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli};
121bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
12261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstruct jz4740_mmc_host {
12361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_host *mmc;
12461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct platform_device *pdev;
12561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_platform_data *pdata;
12661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct clk *clk;
12761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
12861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int irq;
12961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int card_detect_irq;
13061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
13161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	void __iomem *base;
1327ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	struct resource *mem_res;
13361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_request *req;
13461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_command *cmd;
13561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
13661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned long waiting;
13761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
13861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint32_t cmdat;
13961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
14061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint16_t irq_mask;
14161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
14261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	spinlock_t lock;
14361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
14461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct timer_list timeout_timer;
14561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct sg_mapping_iter miter;
14661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	enum jz4740_mmc_state state;
1477ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1487ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	/* DMA support */
1497ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	struct dma_chan *dma_rx;
1507ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	struct dma_chan *dma_tx;
151bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct jz4740_mmc_host_next next_data;
1527ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	bool use_dma;
1537ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	int sg_len;
1547ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1557ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/* The DMA trigger level is 8 words, that is to say, the DMA read
1567ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli * trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write
1577ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli * trigger is when data words in MSC_TXFIFO is < 8.
1587ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli */
1597ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli#define JZ4740_MMC_FIFO_HALF_SIZE 8
16061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen};
16161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
1627ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/*----------------------------------------------------------------------------*/
1637ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/* DMA infrastructure */
1647ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1657ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host)
1667ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{
1677ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	if (!host->use_dma)
1687ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		return;
1697ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1707ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_release_channel(host->dma_tx);
1717ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_release_channel(host->dma_rx);
1727ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli}
1737ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1747ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
1757ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{
1767ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_cap_mask_t mask;
1777ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1787ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_cap_zero(mask);
1797ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_cap_set(DMA_SLAVE, mask);
1807ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1817ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	host->dma_tx = dma_request_channel(mask, NULL, host);
1827ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	if (!host->dma_tx) {
1837ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n");
1847ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		return -ENODEV;
1857ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	}
1867ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1877ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	host->dma_rx = dma_request_channel(mask, NULL, host);
1887ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	if (!host->dma_rx) {
1897ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n");
1907ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		goto free_master_write;
1917ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	}
1927ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
193bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	/* Initialize DMA pre request cookie */
194bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	host->next_data.cookie = 1;
195bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
1967ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	return 0;
1977ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
1987ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelifree_master_write:
1997ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_release_channel(host->dma_tx);
2007ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	return -ENODEV;
2017ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli}
2027ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
2037ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic inline int jz4740_mmc_get_dma_dir(struct mmc_data *data)
2047ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{
2057ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	return (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
2067ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli}
2077ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
208bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
209bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli						       struct mmc_data *data)
210bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{
211bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	return (data->flags & MMC_DATA_READ) ? host->dma_rx : host->dma_tx;
212bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli}
213bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
2147ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
2157ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli				 struct mmc_data *data)
2167ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{
217bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
2187ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
2197ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
2207ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
2217ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli}
2227ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
223bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli/* Prepares DMA data for current/next transfer, returns non-zero on failure */
224bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
225bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				       struct mmc_data *data,
226bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				       struct jz4740_mmc_host_next *next,
227bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				       struct dma_chan *chan)
228bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{
229bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct jz4740_mmc_host_next *next_data = &host->next_data;
230bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
231bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	int sg_len;
232bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
233bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (!next && data->host_cookie &&
234bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	    data->host_cookie != host->next_data.cookie) {
235bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		dev_warn(mmc_dev(host->mmc),
236bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 "[%s] invalid cookie: data->host_cookie %d host->next_data.cookie %d\n",
237bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 __func__,
238bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 data->host_cookie,
239bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 host->next_data.cookie);
240bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		data->host_cookie = 0;
241bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	}
242bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
243bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	/* Check if next job is already prepared */
244bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (next || data->host_cookie != host->next_data.cookie) {
245bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		sg_len = dma_map_sg(chan->device->dev,
246bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				    data->sg,
247bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				    data->sg_len,
248bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				    dir);
249bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
250bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	} else {
251bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		sg_len = next_data->sg_len;
252bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		next_data->sg_len = 0;
253bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	}
254bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
255bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (sg_len <= 0) {
256bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		dev_err(mmc_dev(host->mmc),
257bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			"Failed to map scatterlist for DMA operation\n");
258bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		return -EINVAL;
259bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	}
260bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
261bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (next) {
262bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		next->sg_len = sg_len;
263bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
264bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	} else
265bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		host->sg_len = sg_len;
266bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
267bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	return 0;
268bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli}
269bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
2707ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
2717ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli					 struct mmc_data *data)
2727ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{
273bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	int ret;
2747ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	struct dma_chan *chan;
2757ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	struct dma_async_tx_descriptor *desc;
2767ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	struct dma_slave_config conf = {
2777ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
2787ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
2797ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		.src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
2807ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		.dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
2817ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	};
2827ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
283bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (data->flags & MMC_DATA_WRITE) {
2847ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		conf.direction = DMA_MEM_TO_DEV;
2857ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO;
2867ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT;
2877ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		chan = host->dma_tx;
2887ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	} else {
2897ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		conf.direction = DMA_DEV_TO_MEM;
2907ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO;
2917ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE;
2927ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		chan = host->dma_rx;
2937ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	}
2947ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
295bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	ret = jz4740_mmc_prepare_dma_data(host, data, NULL, chan);
296bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (ret)
297bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		return ret;
2987ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
2997ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dmaengine_slave_config(chan, &conf);
3007ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	desc = dmaengine_prep_slave_sg(chan,
3017ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli				       data->sg,
3027ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli				       host->sg_len,
3037ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli				       conf.direction,
3047ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
3057ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	if (!desc) {
3067ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		dev_err(mmc_dev(host->mmc),
3077ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			"Failed to allocate DMA %s descriptor",
3087ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			 conf.direction == DMA_MEM_TO_DEV ? "TX" : "RX");
3097ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		goto dma_unmap;
3107ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	}
3117ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
3127ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dmaengine_submit(desc);
3137ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dma_async_issue_pending(chan);
3147ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
3157ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	return 0;
3167ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
3177ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelidma_unmap:
3187ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	jz4740_mmc_dma_unmap(host, data);
3197ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	return -ENOMEM;
3207ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli}
3217ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
322bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic void jz4740_mmc_pre_request(struct mmc_host *mmc,
323bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				   struct mmc_request *mrq,
324bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				   bool is_first_req)
325bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{
326bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct jz4740_mmc_host *host = mmc_priv(mmc);
327bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct mmc_data *data = mrq->data;
328bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct jz4740_mmc_host_next *next_data = &host->next_data;
329bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
330bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	BUG_ON(data->host_cookie);
331bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
332bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (host->use_dma) {
333bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
334bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
335bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan))
336bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			data->host_cookie = 0;
337bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	}
338bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli}
339bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
340bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic void jz4740_mmc_post_request(struct mmc_host *mmc,
341bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				    struct mmc_request *mrq,
342bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli				    int err)
343bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{
344bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct jz4740_mmc_host *host = mmc_priv(mmc);
345bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	struct mmc_data *data = mrq->data;
346bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
347bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (host->use_dma && data->host_cookie) {
348bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		jz4740_mmc_dma_unmap(host, data);
349bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		data->host_cookie = 0;
350bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	}
351bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
352bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	if (err) {
353bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
354bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
355bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli		dmaengine_terminate_all(chan);
356bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	}
357bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli}
358bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli
3597ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/*----------------------------------------------------------------------------*/
3607ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
36161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
36261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned int irq, bool enabled)
36361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
36461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned long flags;
36561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
36661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	spin_lock_irqsave(&host->lock, flags);
36761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (enabled)
36861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		host->irq_mask &= ~irq;
36961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	else
37061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		host->irq_mask |= irq;
37161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	spin_unlock_irqrestore(&host->lock, flags);
37261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
37361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
37461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
37561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
37661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host,
37761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	bool start_transfer)
37861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
37961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint16_t val = JZ_MMC_STRPCL_CLOCK_START;
38061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
38161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (start_transfer)
38261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		val |= JZ_MMC_STRPCL_START_OP;
38361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
38461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writew(val, host->base + JZ_REG_MMC_STRPCL);
38561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
38661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
38761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host)
38861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
38961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint32_t status;
39061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned int timeout = 1000;
39161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
39261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL);
39361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	do {
39461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		status = readl(host->base + JZ_REG_MMC_STATUS);
39561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	} while (status & JZ_MMC_STATUS_CLK_EN && --timeout);
39661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
39761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
39861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_reset(struct jz4740_mmc_host *host)
39961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
40061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint32_t status;
40161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned int timeout = 1000;
40261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
40361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL);
40461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	udelay(10);
40561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	do {
40661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		status = readl(host->base + JZ_REG_MMC_STATUS);
40761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	} while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout);
40861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
40961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
41061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
41161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
41261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_request *req;
41361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
41461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	req = host->req;
41561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->req = NULL;
41661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
41761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc_request_done(host->mmc, req);
41861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
41961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
42061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host,
42161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned int irq)
42261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
42361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned int timeout = 0x800;
42461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint16_t status;
42561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
42661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	do {
42761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		status = readw(host->base + JZ_REG_MMC_IREG);
42861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	} while (!(status & irq) && --timeout);
42961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
43061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (timeout == 0) {
43161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		set_bit(0, &host->waiting);
43261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		mod_timer(&host->timeout_timer, jiffies + 5*HZ);
43361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		jz4740_mmc_set_irq_enabled(host, irq, true);
43461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		return true;
43561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
43661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
43761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return false;
43861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
43961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
44061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host,
44161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_data *data)
44261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
44361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int status;
44461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
44561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	status = readl(host->base + JZ_REG_MMC_STATUS);
44661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) {
44761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) {
44861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			host->req->cmd->error = -ETIMEDOUT;
44961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			data->error = -ETIMEDOUT;
45061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		} else {
45161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			host->req->cmd->error = -EIO;
45261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			data->error = -EIO;
45361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
4548a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil	} else if (status & JZ_MMC_STATUS_READ_ERROR_MASK) {
4558a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil		if (status & (JZ_MMC_STATUS_TIMEOUT_READ)) {
4568a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil			host->req->cmd->error = -ETIMEDOUT;
4578a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil			data->error = -ETIMEDOUT;
4588a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil		} else {
4598a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil			host->req->cmd->error = -EIO;
4608a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil			data->error = -EIO;
4618a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil		}
46261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
46361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
46461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
46561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic bool jz4740_mmc_write_data(struct jz4740_mmc_host *host,
46661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_data *data)
46761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
46861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct sg_mapping_iter *miter = &host->miter;
46961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO;
47061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint32_t *buf;
47161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	bool timeout;
47261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	size_t i, j;
47361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
47461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	while (sg_miter_next(miter)) {
47561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		buf = miter->addr;
47661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		i = miter->length / 4;
47761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		j = i / 8;
47861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		i = i & 0x7;
47961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		while (j) {
48061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
48161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			if (unlikely(timeout))
48261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				goto poll_timeout;
48361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
48461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[0], fifo_addr);
48561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[1], fifo_addr);
48661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[2], fifo_addr);
48761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[3], fifo_addr);
48861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[4], fifo_addr);
48961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[5], fifo_addr);
49061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[6], fifo_addr);
49161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writel(buf[7], fifo_addr);
49261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf += 8;
49361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			--j;
49461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
49561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (unlikely(i)) {
49661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
49761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			if (unlikely(timeout))
49861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				goto poll_timeout;
49961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
50061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			while (i) {
50161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				writel(*buf, fifo_addr);
50261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				++buf;
50361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				--i;
50461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			}
50561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
50661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		data->bytes_xfered += miter->length;
50761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
50861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	sg_miter_stop(miter);
50961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
51061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return false;
51161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
51261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenpoll_timeout:
51361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	miter->consumed = (void *)buf - miter->addr;
51461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	data->bytes_xfered += miter->consumed;
51561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	sg_miter_stop(miter);
51661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
51761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return true;
51861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
51961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
52061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic bool jz4740_mmc_read_data(struct jz4740_mmc_host *host,
52161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				struct mmc_data *data)
52261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
52361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct sg_mapping_iter *miter = &host->miter;
52461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO;
52561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint32_t *buf;
52661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint32_t d;
52761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint16_t status;
52861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	size_t i, j;
52961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	unsigned int timeout;
53061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
53161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	while (sg_miter_next(miter)) {
53261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		buf = miter->addr;
53361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		i = miter->length;
53461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		j = i / 32;
53561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		i = i & 0x1f;
53661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		while (j) {
53761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
53861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			if (unlikely(timeout))
53961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				goto poll_timeout;
54061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
54161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[0] = readl(fifo_addr);
54261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[1] = readl(fifo_addr);
54361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[2] = readl(fifo_addr);
54461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[3] = readl(fifo_addr);
54561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[4] = readl(fifo_addr);
54661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[5] = readl(fifo_addr);
54761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[6] = readl(fifo_addr);
54861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf[7] = readl(fifo_addr);
54961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
55061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			buf += 8;
55161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			--j;
55261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
55361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
55461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (unlikely(i)) {
55561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
55661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			if (unlikely(timeout))
55761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				goto poll_timeout;
55861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
55961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			while (i >= 4) {
56061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				*buf++ = readl(fifo_addr);
56161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				i -= 4;
56261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			}
56361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			if (unlikely(i > 0)) {
56461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				d = readl(fifo_addr);
56561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				memcpy(buf, &d, i);
56661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			}
56761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
56861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		data->bytes_xfered += miter->length;
56961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
57061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		/* This can go away once MIPS implements
57161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		 * flush_kernel_dcache_page */
57261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		flush_dcache_page(miter->page);
57361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
57461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	sg_miter_stop(miter);
57561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
57661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	/* For whatever reason there is sometime one word more in the fifo then
57761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	 * requested */
57861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	timeout = 1000;
57961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	status = readl(host->base + JZ_REG_MMC_STATUS);
58061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) {
58161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		d = readl(fifo_addr);
58261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		status = readl(host->base + JZ_REG_MMC_STATUS);
58361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
58461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
58561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return false;
58661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
58761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenpoll_timeout:
58861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	miter->consumed = (void *)buf - miter->addr;
58961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	data->bytes_xfered += miter->consumed;
59061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	sg_miter_stop(miter);
59161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
59261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return true;
59361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
59461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
59561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_timeout(unsigned long data)
59661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
59761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data;
59861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
59961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (!test_and_clear_bit(0, &host->waiting))
60061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		return;
60161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
60261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false);
60361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
60461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->req->cmd->error = -ETIMEDOUT;
60561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_request_done(host);
60661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
60761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
60861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_read_response(struct jz4740_mmc_host *host,
60961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_command *cmd)
61061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
61161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int i;
61261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint16_t tmp;
61361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO;
61461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
61561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (cmd->flags & MMC_RSP_136) {
61661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		tmp = readw(fifo_addr);
61761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		for (i = 0; i < 4; ++i) {
61861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			cmd->resp[i] = tmp << 24;
61961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			tmp = readw(fifo_addr);
62061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			cmd->resp[i] |= tmp << 8;
62161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			tmp = readw(fifo_addr);
62261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			cmd->resp[i] |= tmp >> 8;
62361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
62461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	} else {
62561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmd->resp[0] = readw(fifo_addr) << 24;
62661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmd->resp[0] |= readw(fifo_addr) << 8;
62761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmd->resp[0] |= readw(fifo_addr) & 0xff;
62861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
62961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
63061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
63161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
63261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_command *cmd)
63361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
63461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint32_t cmdat = host->cmdat;
63561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
63661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->cmdat &= ~JZ_MMC_CMDAT_INIT;
63761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_clock_disable(host);
63861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
63961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->cmd = cmd;
64061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
64161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (cmd->flags & MMC_RSP_BUSY)
64261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmdat |= JZ_MMC_CMDAT_BUSY;
64361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
64461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	switch (mmc_resp_type(cmd)) {
64561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_RSP_R1B:
64661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_RSP_R1:
64761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmdat |= JZ_MMC_CMDAT_RSP_R1;
64861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
64961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_RSP_R2:
65061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmdat |= JZ_MMC_CMDAT_RSP_R2;
65161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
65261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_RSP_R3:
65361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmdat |= JZ_MMC_CMDAT_RSP_R3;
65461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
65561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	default:
65661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
65761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
65861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
65961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (cmd->data) {
66061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		cmdat |= JZ_MMC_CMDAT_DATA_EN;
66161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (cmd->data->flags & MMC_DATA_WRITE)
66261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			cmdat |= JZ_MMC_CMDAT_WRITE;
66361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (cmd->data->flags & MMC_DATA_STREAM)
66461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			cmdat |= JZ_MMC_CMDAT_STREAM;
6657ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		if (host->use_dma)
6667ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			cmdat |= JZ_MMC_CMDAT_DMA_EN;
66761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
66861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN);
66961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB);
67061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
67161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
67261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD);
67361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writel(cmd->arg, host->base + JZ_REG_MMC_ARG);
67461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writel(cmdat, host->base + JZ_REG_MMC_CMDAT);
67561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
67661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_clock_enable(host, 1);
67761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
67861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
67961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host)
68061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
68161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_command *cmd = host->req->cmd;
68261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_data *data = cmd->data;
68361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int direction;
68461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
68561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (data->flags & MMC_DATA_READ)
68661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		direction = SG_MITER_TO_SG;
68761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	else
68861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		direction = SG_MITER_FROM_SG;
68961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
69061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	sg_miter_start(&host->miter, data->sg, data->sg_len, direction);
69161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
69261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
69361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
69461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
69561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
69661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid;
69761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_command *cmd = host->req->cmd;
69861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_request *req = host->req;
6997ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	struct mmc_data *data = cmd->data;
70061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	bool timeout = false;
70161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
70261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (cmd->error)
70361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		host->state = JZ4740_MMC_STATE_DONE;
70461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
70561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	switch (host->state) {
70661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case JZ4740_MMC_STATE_READ_RESPONSE:
70761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (cmd->flags & MMC_RSP_PRESENT)
70861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			jz4740_mmc_read_response(host, cmd);
70961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
7107ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		if (!data)
71161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			break;
71261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
71361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		jz_mmc_prepare_data_transfer(host);
71461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
71561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case JZ4740_MMC_STATE_TRANSFER_DATA:
7167ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		if (host->use_dma) {
717bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			/* Use DMA if enabled.
718bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 * Data transfer direction is defined later by
719bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 * relying on data flags in
720bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 * jz4740_mmc_prepare_dma_data() and
721bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 * jz4740_mmc_start_dma_transfer().
7227ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			 */
7237ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			timeout = jz4740_mmc_start_dma_transfer(host, data);
7247ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			data->bytes_xfered = data->blocks * data->blksz;
7257ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		} else if (data->flags & MMC_DATA_READ)
726bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			/* Use PIO if DMA is not enabled.
727bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 * Data transfer direction was defined before
728bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 * by relying on data flags in
729bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli			 * jz_mmc_prepare_data_transfer().
7307ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			 */
7317ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			timeout = jz4740_mmc_read_data(host, data);
73261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		else
7337ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli			timeout = jz4740_mmc_write_data(host, data);
73461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
73561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (unlikely(timeout)) {
73661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			host->state = JZ4740_MMC_STATE_TRANSFER_DATA;
73761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			break;
73861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
73961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
7407ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		jz4740_mmc_transfer_check_state(host, data);
74161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
74261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
74361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (unlikely(timeout)) {
74461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			host->state = JZ4740_MMC_STATE_SEND_STOP;
74561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			break;
74661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
74761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
74861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
74961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case JZ4740_MMC_STATE_SEND_STOP:
75061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (!req->stop)
75161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			break;
75261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
75361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		jz4740_mmc_send_command(host, req->stop);
75461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
7551acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith		if (mmc_resp_type(req->stop) & MMC_RSP_BUSY) {
7561acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith			timeout = jz4740_mmc_poll_irq(host,
7571acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith						      JZ_MMC_IRQ_PRG_DONE);
7581acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith			if (timeout) {
7591acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith				host->state = JZ4740_MMC_STATE_DONE;
7601acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith				break;
7611acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith			}
76261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
76361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case JZ4740_MMC_STATE_DONE:
76461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
76561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
76661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
76761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (!timeout)
76861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		jz4740_mmc_request_done(host);
76961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
77061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return IRQ_HANDLED;
77161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
77261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
77361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic irqreturn_t jz_mmc_irq(int irq, void *devid)
77461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
77561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = devid;
77661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_command *cmd = host->cmd;
77761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	uint16_t irq_reg, status, tmp;
77861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
77961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	irq_reg = readw(host->base + JZ_REG_MMC_IREG);
78061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
78161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	tmp = irq_reg;
78261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	irq_reg &= ~host->irq_mask;
78361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
78461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ |
78561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
78661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
78761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (tmp != irq_reg)
78861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG);
78961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
79061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (irq_reg & JZ_MMC_IRQ_SDIO) {
79161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG);
79261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		mmc_signal_sdio_irq(host->mmc);
79361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		irq_reg &= ~JZ_MMC_IRQ_SDIO;
79461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
79561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
79661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (host->req && cmd && irq_reg) {
79761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (test_and_clear_bit(0, &host->waiting)) {
79861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			del_timer(&host->timeout_timer);
79961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
80061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			status = readl(host->base + JZ_REG_MMC_STATUS);
80161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
80261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
80361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen					cmd->error = -ETIMEDOUT;
80461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			} else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
80561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen					cmd->error = -EIO;
80661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			} else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
80761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen				    JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
80861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen					if (cmd->data)
80961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen							cmd->data->error = -EIO;
81061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen					cmd->error = -EIO;
81161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			}
81261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
81361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			jz4740_mmc_set_irq_enabled(host, irq_reg, false);
81461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			writew(irq_reg, host->base + JZ_REG_MMC_IREG);
81561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
81661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			return IRQ_WAKE_THREAD;
81761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		}
81861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
81961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
82061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return IRQ_HANDLED;
82161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
82261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
82361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
82461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
82561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int div = 0;
82661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int real_rate;
82761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
82861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_clock_disable(host);
82961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	clk_set_rate(host->clk, JZ_MMC_CLK_RATE);
83061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
83161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	real_rate = clk_get_rate(host->clk);
83261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
83361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	while (real_rate > rate && div < 7) {
83461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		++div;
83561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		real_rate >>= 1;
83661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
83761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
83861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writew(div, host->base + JZ_REG_MMC_CLKRT);
83961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return real_rate;
84061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
84161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
84261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
84361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
84461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = mmc_priv(mmc);
84561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
84661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->req = req;
84761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
84861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writew(0xffff, host->base + JZ_REG_MMC_IREG);
84961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
85061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
85161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true);
85261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
85361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->state = JZ4740_MMC_STATE_READ_RESPONSE;
85461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	set_bit(0, &host->waiting);
85561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mod_timer(&host->timeout_timer, jiffies + 5*HZ);
85661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_send_command(host, req->cmd);
85761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
85861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
85961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
86061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
86161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = mmc_priv(mmc);
86261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (ios->clock)
86361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		jz4740_mmc_set_clock_rate(host, ios->clock);
86461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
86561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	switch (ios->power_mode) {
86661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_POWER_UP:
86761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		jz4740_mmc_reset(host);
86861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (gpio_is_valid(host->pdata->gpio_power))
86961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			gpio_set_value(host->pdata->gpio_power,
87061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen					!host->pdata->power_active_low);
87161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		host->cmdat |= JZ_MMC_CMDAT_INIT;
872fca9661c6c8926171a49f6ac57adc65290f10cafLars-Peter Clausen		clk_prepare_enable(host->clk);
87361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
87461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_POWER_ON:
87561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
87661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	default:
87761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		if (gpio_is_valid(host->pdata->gpio_power))
87861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			gpio_set_value(host->pdata->gpio_power,
87961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen					host->pdata->power_active_low);
880fca9661c6c8926171a49f6ac57adc65290f10cafLars-Peter Clausen		clk_disable_unprepare(host->clk);
88161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
88261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
88361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
88461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	switch (ios->bus_width) {
88561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_BUS_WIDTH_1:
88661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
88761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
88861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	case MMC_BUS_WIDTH_4:
88961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
89061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
89161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	default:
89261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		break;
89361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
89461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
89561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
89661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
89761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
89861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = mmc_priv(mmc);
89961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
90061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
90161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
90261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic const struct mmc_host_ops jz4740_mmc_ops = {
90361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	.request	= jz4740_mmc_request,
904bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	.pre_req	= jz4740_mmc_pre_request,
905bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli	.post_req	= jz4740_mmc_post_request,
90661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	.set_ios	= jz4740_mmc_set_ios,
90758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	.get_ro		= mmc_gpio_get_ro,
90858e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	.get_cd		= mmc_gpio_get_cd,
90961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
91061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen};
91161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
91261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
91361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ_GPIO_BULK_PIN(MSC_CMD),
91461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ_GPIO_BULK_PIN(MSC_CLK),
91561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ_GPIO_BULK_PIN(MSC_DATA0),
91661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ_GPIO_BULK_PIN(MSC_DATA1),
91761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ_GPIO_BULK_PIN(MSC_DATA2),
91861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	JZ_GPIO_BULK_PIN(MSC_DATA3),
91961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen};
92061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
921c3be1efd41a97f93be390240387d356a07b664c7Bill Pembertonstatic int jz4740_mmc_request_gpio(struct device *dev, int gpio,
92261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	const char *name, bool output, int value)
92361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
92461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int ret;
92561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
92661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (!gpio_is_valid(gpio))
92761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		return 0;
92861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
92961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	ret = gpio_request(gpio, name);
93061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (ret) {
93161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		dev_err(dev, "Failed to request %s gpio: %d\n", name, ret);
93261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		return ret;
93361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
93461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
93561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (output)
93661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		gpio_direction_output(gpio, value);
93761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	else
93861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		gpio_direction_input(gpio);
93961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
94061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return 0;
94161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
94261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
94358e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausenstatic int jz4740_mmc_request_gpios(struct mmc_host *mmc,
94458e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	struct platform_device *pdev)
94561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
94661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
94758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	int ret = 0;
94861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
94961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (!pdata)
95061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		return 0;
95161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
95258e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	if (!pdata->card_detect_active_low)
95358e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen		mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
95458e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	if (!pdata->read_only_active_low)
95558e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen		mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
95661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
95758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	if (gpio_is_valid(pdata->gpio_card_detect)) {
958214fc309d1387e822d606a33a10e31cacfe83520Laurent Pinchart		ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0);
95958e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen		if (ret)
96058e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen			return ret;
96158e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	}
96261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
96358e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	if (gpio_is_valid(pdata->gpio_read_only)) {
96458e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen		ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only);
96558e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen		if (ret)
96658e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen			return ret;
96761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
96861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
96958e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
97058e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen			"MMC read only", true, pdata->power_active_low);
97161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
97261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
97361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_free_gpios(struct platform_device *pdev)
97461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
97561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
97661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
97761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (!pdata)
97861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		return;
97961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
98061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (gpio_is_valid(pdata->gpio_power))
98161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		gpio_free(pdata->gpio_power);
98261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
98361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
98461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
98561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
98661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
98761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (host->pdata && host->pdata->data_1bit)
98861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		num_pins -= 3;
98961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
99061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return num_pins;
99161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
99261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
993c3be1efd41a97f93be390240387d356a07b664c7Bill Pembertonstatic int jz4740_mmc_probe(struct platform_device* pdev)
99461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
99561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	int ret;
99661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct mmc_host *mmc;
99761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host;
99861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_platform_data *pdata;
99961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
100061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	pdata = pdev->dev.platform_data;
100161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
100261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
100361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (!mmc) {
100461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		dev_err(&pdev->dev, "Failed to alloc mmc host structure\n");
100561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		return -ENOMEM;
100661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
100761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
100861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host = mmc_priv(mmc);
100961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->pdata = pdata;
101061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
101161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->irq = platform_get_irq(pdev, 0);
101261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (host->irq < 0) {
101361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		ret = host->irq;
101461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
101561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		goto err_free_host;
101661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
101761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
1018017d84bd45d1d2e584d01f3875aacbfa481aa95aLars-Peter Clausen	host->clk = devm_clk_get(&pdev->dev, "mmc");
10193119cbda858fc9ae10a69919e5f278abd6d93bb5Jamie Iles	if (IS_ERR(host->clk)) {
10203119cbda858fc9ae10a69919e5f278abd6d93bb5Jamie Iles		ret = PTR_ERR(host->clk);
102161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		dev_err(&pdev->dev, "Failed to get mmc clock\n");
102261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		goto err_free_host;
102361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
102461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
10257ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	host->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
10267ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	host->base = devm_ioremap_resource(&pdev->dev, host->mem_res);
10273e7e8c18a15102c3042206c067356e6c39961725Wei Yongjun	if (IS_ERR(host->base)) {
10283e7e8c18a15102c3042206c067356e6c39961725Wei Yongjun		ret = PTR_ERR(host->base);
10297ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		dev_err(&pdev->dev, "Failed to ioremap base memory\n");
1030017d84bd45d1d2e584d01f3875aacbfa481aa95aLars-Peter Clausen		goto err_free_host;
103161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
103261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
103361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
103461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (ret) {
103561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
1036017d84bd45d1d2e584d01f3875aacbfa481aa95aLars-Peter Clausen		goto err_free_host;
103761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
103861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
103958e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen	ret = jz4740_mmc_request_gpios(mmc, pdev);
104061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (ret)
104161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		goto err_gpio_bulk_free;
104261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
104361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->ops = &jz4740_mmc_ops;
104461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->f_min = JZ_MMC_CLK_RATE / 128;
104561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->f_max = JZ_MMC_CLK_RATE;
104661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
104761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA;
104861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->caps |= MMC_CAP_SDIO_IRQ;
104961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
105061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->max_blk_size = (1 << 10) - 1;
105161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->max_blk_count = (1 << 15) - 1;
105261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
105361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
1054a36274e0184193e393fb82957925c3981a6b0477Martin K. Petersen	mmc->max_segs = 128;
105561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc->max_seg_size = mmc->max_req_size;
105661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
105761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->mmc = mmc;
105861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->pdev = pdev;
105961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	spin_lock_init(&host->lock);
106061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	host->irq_mask = 0xffff;
106161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
106261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
106361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			dev_name(&pdev->dev), host);
106461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (ret) {
106561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
106658e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen		goto err_free_gpios;
106761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
106861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
106961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_reset(host);
107061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_clock_disable(host);
107161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	setup_timer(&host->timeout_timer, jz4740_mmc_timeout,
107261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen			(unsigned long)host);
107361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	/* It is not important when it times out, it just needs to timeout. */
107461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	set_timer_slack(&host->timeout_timer, HZ);
107561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
10767ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	host->use_dma = true;
10777ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0)
10787ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		host->use_dma = false;
10797ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
108061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	platform_set_drvdata(pdev, host);
108161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	ret = mmc_add_host(mmc);
108261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
108361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	if (ret) {
108461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret);
108561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		goto err_free_irq;
108661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	}
108761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n");
108861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
10897ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	dev_info(&pdev->dev, "Using %s, %d-bit mode\n",
10907ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		 host->use_dma ? "DMA" : "PIO",
10917ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		 (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1);
10927ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
109361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return 0;
109461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
109561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_free_irq:
109661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	free_irq(host->irq, host);
109761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_free_gpios:
109861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_free_gpios(pdev);
109961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_gpio_bulk_free:
11007ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	if (host->use_dma)
11017ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		jz4740_mmc_release_dma_channels(host);
110261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
110361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_free_host:
110461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc_free_host(mmc);
110561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
110661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return ret;
110761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
110861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
11096e0ee714fdab0568c3487455951dea2673e9557fBill Pembertonstatic int jz4740_mmc_remove(struct platform_device *pdev)
111061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
111161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = platform_get_drvdata(pdev);
111261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
111361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	del_timer_sync(&host->timeout_timer);
111461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_set_irq_enabled(host, 0xff, false);
111561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_reset(host);
111661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
111761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc_remove_host(host->mmc);
111861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
111961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	free_irq(host->irq, host);
112061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
112161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz4740_mmc_free_gpios(pdev);
112261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
112361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
11247ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli	if (host->use_dma)
11257ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli		jz4740_mmc_release_dma_channels(host);
11267ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli
112761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	mmc_free_host(host->mmc);
112861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
112961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return 0;
113061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
113161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
11325d5c0350fc9533a1af3a43ee2331fec412679fcfLars-Peter Clausen#ifdef CONFIG_PM_SLEEP
113361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
113461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic int jz4740_mmc_suspend(struct device *dev)
113561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
113661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
113761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
113861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
113961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
114061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return 0;
114161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
114261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
114361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic int jz4740_mmc_resume(struct device *dev)
114461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{
114561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
114661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
114761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
114861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
114961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	return 0;
115061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}
115161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
11525d5c0350fc9533a1af3a43ee2331fec412679fcfLars-Peter Clausenstatic SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
11535d5c0350fc9533a1af3a43ee2331fec412679fcfLars-Peter Clausen	jz4740_mmc_resume);
115461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops)
115561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#else
115661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ4740_MMC_PM_OPS NULL
115761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#endif
115861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
115961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic struct platform_driver jz4740_mmc_driver = {
116061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	.probe = jz4740_mmc_probe,
11610433c14356702e296f474f77ebd42f0a9d9a5487Bill Pemberton	.remove = jz4740_mmc_remove,
116261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	.driver = {
116361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		.name = "jz4740-mmc",
116461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen		.pm = JZ4740_MMC_PM_OPS,
116561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen	},
116661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen};
116761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
1168d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(jz4740_mmc_driver);
116961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen
117061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter ClausenMODULE_DESCRIPTION("JZ4740 SD/MMC controller driver");
117161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter ClausenMODULE_LICENSE("GPL");
117261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter ClausenMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
1173