xref: /openbmc/linux/drivers/mmc/host/atmel-mci.c (revision 266ac3f2)
17d2be074SHaavard Skinnemoen /*
27d2be074SHaavard Skinnemoen  * Atmel MultiMedia Card Interface driver
37d2be074SHaavard Skinnemoen  *
47d2be074SHaavard Skinnemoen  * Copyright (C) 2004-2008 Atmel Corporation
57d2be074SHaavard Skinnemoen  *
67d2be074SHaavard Skinnemoen  * This program is free software; you can redistribute it and/or modify
77d2be074SHaavard Skinnemoen  * it under the terms of the GNU General Public License version 2 as
87d2be074SHaavard Skinnemoen  * published by the Free Software Foundation.
97d2be074SHaavard Skinnemoen  */
107d2be074SHaavard Skinnemoen #include <linux/blkdev.h>
117d2be074SHaavard Skinnemoen #include <linux/clk.h>
12deec9ae3SHaavard Skinnemoen #include <linux/debugfs.h>
137d2be074SHaavard Skinnemoen #include <linux/device.h>
1465e8b083SHaavard Skinnemoen #include <linux/dmaengine.h>
1565e8b083SHaavard Skinnemoen #include <linux/dma-mapping.h>
16fbfca4b8SBen Nizette #include <linux/err.h>
173c26e170SDavid Brownell #include <linux/gpio.h>
187d2be074SHaavard Skinnemoen #include <linux/init.h>
197d2be074SHaavard Skinnemoen #include <linux/interrupt.h>
207d2be074SHaavard Skinnemoen #include <linux/ioport.h>
217d2be074SHaavard Skinnemoen #include <linux/module.h>
227d2be074SHaavard Skinnemoen #include <linux/platform_device.h>
237d2be074SHaavard Skinnemoen #include <linux/scatterlist.h>
24deec9ae3SHaavard Skinnemoen #include <linux/seq_file.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
26deec9ae3SHaavard Skinnemoen #include <linux/stat.h>
277d2be074SHaavard Skinnemoen 
287d2be074SHaavard Skinnemoen #include <linux/mmc/host.h>
292f1d7918SNicolas Ferre #include <linux/mmc/sdio.h>
302635d1baSNicolas Ferre 
312635d1baSNicolas Ferre #include <mach/atmel-mci.h>
32c42aa775SNicolas Ferre #include <linux/atmel-mci.h>
337d2be074SHaavard Skinnemoen 
347d2be074SHaavard Skinnemoen #include <asm/io.h>
357d2be074SHaavard Skinnemoen #include <asm/unaligned.h>
367d2be074SHaavard Skinnemoen 
3704d699c3SRob Emanuele #include <mach/cpu.h>
383663b736SHaavard Skinnemoen #include <mach/board.h>
397d2be074SHaavard Skinnemoen 
407d2be074SHaavard Skinnemoen #include "atmel-mci-regs.h"
417d2be074SHaavard Skinnemoen 
427d2be074SHaavard Skinnemoen #define ATMCI_DATA_ERROR_FLAGS	(MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
4365e8b083SHaavard Skinnemoen #define ATMCI_DMA_THRESHOLD	16
447d2be074SHaavard Skinnemoen 
457d2be074SHaavard Skinnemoen enum {
467d2be074SHaavard Skinnemoen 	EVENT_CMD_COMPLETE = 0,
477d2be074SHaavard Skinnemoen 	EVENT_XFER_COMPLETE,
48c06ad258SHaavard Skinnemoen 	EVENT_DATA_COMPLETE,
49c06ad258SHaavard Skinnemoen 	EVENT_DATA_ERROR,
50c06ad258SHaavard Skinnemoen };
51c06ad258SHaavard Skinnemoen 
52c06ad258SHaavard Skinnemoen enum atmel_mci_state {
53965ebf33SHaavard Skinnemoen 	STATE_IDLE = 0,
54965ebf33SHaavard Skinnemoen 	STATE_SENDING_CMD,
55c06ad258SHaavard Skinnemoen 	STATE_SENDING_DATA,
56c06ad258SHaavard Skinnemoen 	STATE_DATA_BUSY,
57c06ad258SHaavard Skinnemoen 	STATE_SENDING_STOP,
58c06ad258SHaavard Skinnemoen 	STATE_DATA_ERROR,
597d2be074SHaavard Skinnemoen };
607d2be074SHaavard Skinnemoen 
6165e8b083SHaavard Skinnemoen struct atmel_mci_dma {
6265e8b083SHaavard Skinnemoen #ifdef CONFIG_MMC_ATMELMCI_DMA
6365e8b083SHaavard Skinnemoen 	struct dma_chan			*chan;
6465e8b083SHaavard Skinnemoen 	struct dma_async_tx_descriptor	*data_desc;
6565e8b083SHaavard Skinnemoen #endif
6665e8b083SHaavard Skinnemoen };
6765e8b083SHaavard Skinnemoen 
68965ebf33SHaavard Skinnemoen /**
69965ebf33SHaavard Skinnemoen  * struct atmel_mci - MMC controller state shared between all slots
70965ebf33SHaavard Skinnemoen  * @lock: Spinlock protecting the queue and associated data.
71965ebf33SHaavard Skinnemoen  * @regs: Pointer to MMIO registers.
72965ebf33SHaavard Skinnemoen  * @sg: Scatterlist entry currently being processed by PIO code, if any.
73965ebf33SHaavard Skinnemoen  * @pio_offset: Offset into the current scatterlist entry.
74965ebf33SHaavard Skinnemoen  * @cur_slot: The slot which is currently using the controller.
75965ebf33SHaavard Skinnemoen  * @mrq: The request currently being processed on @cur_slot,
76965ebf33SHaavard Skinnemoen  *	or NULL if the controller is idle.
77965ebf33SHaavard Skinnemoen  * @cmd: The command currently being sent to the card, or NULL.
78965ebf33SHaavard Skinnemoen  * @data: The data currently being transferred, or NULL if no data
79965ebf33SHaavard Skinnemoen  *	transfer is in progress.
8065e8b083SHaavard Skinnemoen  * @dma: DMA client state.
8165e8b083SHaavard Skinnemoen  * @data_chan: DMA channel being used for the current data transfer.
82965ebf33SHaavard Skinnemoen  * @cmd_status: Snapshot of SR taken upon completion of the current
83965ebf33SHaavard Skinnemoen  *	command. Only valid when EVENT_CMD_COMPLETE is pending.
84965ebf33SHaavard Skinnemoen  * @data_status: Snapshot of SR taken upon completion of the current
85965ebf33SHaavard Skinnemoen  *	data transfer. Only valid when EVENT_DATA_COMPLETE or
86965ebf33SHaavard Skinnemoen  *	EVENT_DATA_ERROR is pending.
87965ebf33SHaavard Skinnemoen  * @stop_cmdr: Value to be loaded into CMDR when the stop command is
88965ebf33SHaavard Skinnemoen  *	to be sent.
89965ebf33SHaavard Skinnemoen  * @tasklet: Tasklet running the request state machine.
90965ebf33SHaavard Skinnemoen  * @pending_events: Bitmask of events flagged by the interrupt handler
91965ebf33SHaavard Skinnemoen  *	to be processed by the tasklet.
92965ebf33SHaavard Skinnemoen  * @completed_events: Bitmask of events which the state machine has
93965ebf33SHaavard Skinnemoen  *	processed.
94965ebf33SHaavard Skinnemoen  * @state: Tasklet state.
95965ebf33SHaavard Skinnemoen  * @queue: List of slots waiting for access to the controller.
96965ebf33SHaavard Skinnemoen  * @need_clock_update: Update the clock rate before the next request.
97965ebf33SHaavard Skinnemoen  * @need_reset: Reset controller before next request.
98965ebf33SHaavard Skinnemoen  * @mode_reg: Value of the MR register.
9974791a2dSNicolas Ferre  * @cfg_reg: Value of the CFG register.
100965ebf33SHaavard Skinnemoen  * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
101965ebf33SHaavard Skinnemoen  *	rate and timeout calculations.
102965ebf33SHaavard Skinnemoen  * @mapbase: Physical address of the MMIO registers.
103965ebf33SHaavard Skinnemoen  * @mck: The peripheral bus clock hooked up to the MMC controller.
104965ebf33SHaavard Skinnemoen  * @pdev: Platform device associated with the MMC controller.
105965ebf33SHaavard Skinnemoen  * @slot: Slots sharing this MMC controller.
106965ebf33SHaavard Skinnemoen  *
107965ebf33SHaavard Skinnemoen  * Locking
108965ebf33SHaavard Skinnemoen  * =======
109965ebf33SHaavard Skinnemoen  *
110965ebf33SHaavard Skinnemoen  * @lock is a softirq-safe spinlock protecting @queue as well as
111965ebf33SHaavard Skinnemoen  * @cur_slot, @mrq and @state. These must always be updated
112965ebf33SHaavard Skinnemoen  * at the same time while holding @lock.
113965ebf33SHaavard Skinnemoen  *
114965ebf33SHaavard Skinnemoen  * @lock also protects mode_reg and need_clock_update since these are
115965ebf33SHaavard Skinnemoen  * used to synchronize mode register updates with the queue
116965ebf33SHaavard Skinnemoen  * processing.
117965ebf33SHaavard Skinnemoen  *
118965ebf33SHaavard Skinnemoen  * The @mrq field of struct atmel_mci_slot is also protected by @lock,
119965ebf33SHaavard Skinnemoen  * and must always be written at the same time as the slot is added to
120965ebf33SHaavard Skinnemoen  * @queue.
121965ebf33SHaavard Skinnemoen  *
122965ebf33SHaavard Skinnemoen  * @pending_events and @completed_events are accessed using atomic bit
123965ebf33SHaavard Skinnemoen  * operations, so they don't need any locking.
124965ebf33SHaavard Skinnemoen  *
125965ebf33SHaavard Skinnemoen  * None of the fields touched by the interrupt handler need any
126965ebf33SHaavard Skinnemoen  * locking. However, ordering is important: Before EVENT_DATA_ERROR or
127965ebf33SHaavard Skinnemoen  * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
128965ebf33SHaavard Skinnemoen  * interrupts must be disabled and @data_status updated with a
129965ebf33SHaavard Skinnemoen  * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
130965ebf33SHaavard Skinnemoen  * CMDRDY interupt must be disabled and @cmd_status updated with a
131965ebf33SHaavard Skinnemoen  * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
132965ebf33SHaavard Skinnemoen  * bytes_xfered field of @data must be written. This is ensured by
133965ebf33SHaavard Skinnemoen  * using barriers.
134965ebf33SHaavard Skinnemoen  */
1357d2be074SHaavard Skinnemoen struct atmel_mci {
136965ebf33SHaavard Skinnemoen 	spinlock_t		lock;
1377d2be074SHaavard Skinnemoen 	void __iomem		*regs;
1387d2be074SHaavard Skinnemoen 
1397d2be074SHaavard Skinnemoen 	struct scatterlist	*sg;
1407d2be074SHaavard Skinnemoen 	unsigned int		pio_offset;
1417d2be074SHaavard Skinnemoen 
142965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*cur_slot;
1437d2be074SHaavard Skinnemoen 	struct mmc_request	*mrq;
1447d2be074SHaavard Skinnemoen 	struct mmc_command	*cmd;
1457d2be074SHaavard Skinnemoen 	struct mmc_data		*data;
1467d2be074SHaavard Skinnemoen 
14765e8b083SHaavard Skinnemoen 	struct atmel_mci_dma	dma;
14865e8b083SHaavard Skinnemoen 	struct dma_chan		*data_chan;
14965e8b083SHaavard Skinnemoen 
1507d2be074SHaavard Skinnemoen 	u32			cmd_status;
1517d2be074SHaavard Skinnemoen 	u32			data_status;
1527d2be074SHaavard Skinnemoen 	u32			stop_cmdr;
1537d2be074SHaavard Skinnemoen 
1547d2be074SHaavard Skinnemoen 	struct tasklet_struct	tasklet;
1557d2be074SHaavard Skinnemoen 	unsigned long		pending_events;
1567d2be074SHaavard Skinnemoen 	unsigned long		completed_events;
157c06ad258SHaavard Skinnemoen 	enum atmel_mci_state	state;
158965ebf33SHaavard Skinnemoen 	struct list_head	queue;
1597d2be074SHaavard Skinnemoen 
160965ebf33SHaavard Skinnemoen 	bool			need_clock_update;
161965ebf33SHaavard Skinnemoen 	bool			need_reset;
162965ebf33SHaavard Skinnemoen 	u32			mode_reg;
16374791a2dSNicolas Ferre 	u32			cfg_reg;
1647d2be074SHaavard Skinnemoen 	unsigned long		bus_hz;
1657d2be074SHaavard Skinnemoen 	unsigned long		mapbase;
1667d2be074SHaavard Skinnemoen 	struct clk		*mck;
1677d2be074SHaavard Skinnemoen 	struct platform_device	*pdev;
168965ebf33SHaavard Skinnemoen 
169965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot[ATMEL_MCI_MAX_NR_SLOTS];
170965ebf33SHaavard Skinnemoen };
171965ebf33SHaavard Skinnemoen 
172965ebf33SHaavard Skinnemoen /**
173965ebf33SHaavard Skinnemoen  * struct atmel_mci_slot - MMC slot state
174965ebf33SHaavard Skinnemoen  * @mmc: The mmc_host representing this slot.
175965ebf33SHaavard Skinnemoen  * @host: The MMC controller this slot is using.
176965ebf33SHaavard Skinnemoen  * @sdc_reg: Value of SDCR to be written before using this slot.
17788ff82edSAnders Grahn  * @sdio_irq: SDIO irq mask for this slot.
178965ebf33SHaavard Skinnemoen  * @mrq: mmc_request currently being processed or waiting to be
179965ebf33SHaavard Skinnemoen  *	processed, or NULL when the slot is idle.
180965ebf33SHaavard Skinnemoen  * @queue_node: List node for placing this node in the @queue list of
181965ebf33SHaavard Skinnemoen  *	&struct atmel_mci.
182965ebf33SHaavard Skinnemoen  * @clock: Clock rate configured by set_ios(). Protected by host->lock.
183965ebf33SHaavard Skinnemoen  * @flags: Random state bits associated with the slot.
184965ebf33SHaavard Skinnemoen  * @detect_pin: GPIO pin used for card detection, or negative if not
185965ebf33SHaavard Skinnemoen  *	available.
186965ebf33SHaavard Skinnemoen  * @wp_pin: GPIO pin used for card write protect sending, or negative
187965ebf33SHaavard Skinnemoen  *	if not available.
1881c1452beSJonas Larsson  * @detect_is_active_high: The state of the detect pin when it is active.
189965ebf33SHaavard Skinnemoen  * @detect_timer: Timer used for debouncing @detect_pin interrupts.
190965ebf33SHaavard Skinnemoen  */
191965ebf33SHaavard Skinnemoen struct atmel_mci_slot {
192965ebf33SHaavard Skinnemoen 	struct mmc_host		*mmc;
193965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host;
194965ebf33SHaavard Skinnemoen 
195965ebf33SHaavard Skinnemoen 	u32			sdc_reg;
19688ff82edSAnders Grahn 	u32			sdio_irq;
197965ebf33SHaavard Skinnemoen 
198965ebf33SHaavard Skinnemoen 	struct mmc_request	*mrq;
199965ebf33SHaavard Skinnemoen 	struct list_head	queue_node;
200965ebf33SHaavard Skinnemoen 
201965ebf33SHaavard Skinnemoen 	unsigned int		clock;
202965ebf33SHaavard Skinnemoen 	unsigned long		flags;
203965ebf33SHaavard Skinnemoen #define ATMCI_CARD_PRESENT	0
204965ebf33SHaavard Skinnemoen #define ATMCI_CARD_NEED_INIT	1
205965ebf33SHaavard Skinnemoen #define ATMCI_SHUTDOWN		2
206965ebf33SHaavard Skinnemoen 
207965ebf33SHaavard Skinnemoen 	int			detect_pin;
208965ebf33SHaavard Skinnemoen 	int			wp_pin;
2091c1452beSJonas Larsson 	bool			detect_is_active_high;
210965ebf33SHaavard Skinnemoen 
211965ebf33SHaavard Skinnemoen 	struct timer_list	detect_timer;
2127d2be074SHaavard Skinnemoen };
2137d2be074SHaavard Skinnemoen 
2147d2be074SHaavard Skinnemoen #define atmci_test_and_clear_pending(host, event)		\
2157d2be074SHaavard Skinnemoen 	test_and_clear_bit(event, &host->pending_events)
2167d2be074SHaavard Skinnemoen #define atmci_set_completed(host, event)			\
2177d2be074SHaavard Skinnemoen 	set_bit(event, &host->completed_events)
2187d2be074SHaavard Skinnemoen #define atmci_set_pending(host, event)				\
2197d2be074SHaavard Skinnemoen 	set_bit(event, &host->pending_events)
2207d2be074SHaavard Skinnemoen 
221deec9ae3SHaavard Skinnemoen /*
22204d699c3SRob Emanuele  * Enable or disable features/registers based on
22304d699c3SRob Emanuele  * whether the processor supports them
22404d699c3SRob Emanuele  */
22504d699c3SRob Emanuele static bool mci_has_rwproof(void)
22604d699c3SRob Emanuele {
22704d699c3SRob Emanuele 	if (cpu_is_at91sam9261() || cpu_is_at91rm9200())
22804d699c3SRob Emanuele 		return false;
22904d699c3SRob Emanuele 	else
23004d699c3SRob Emanuele 		return true;
23104d699c3SRob Emanuele }
23204d699c3SRob Emanuele 
23304d699c3SRob Emanuele /*
23474791a2dSNicolas Ferre  * The new MCI2 module isn't 100% compatible with the old MCI module,
23574791a2dSNicolas Ferre  * and it has a few nice features which we want to use...
23674791a2dSNicolas Ferre  */
23774791a2dSNicolas Ferre static inline bool atmci_is_mci2(void)
23874791a2dSNicolas Ferre {
23974791a2dSNicolas Ferre 	if (cpu_is_at91sam9g45())
24074791a2dSNicolas Ferre 		return true;
24174791a2dSNicolas Ferre 
24274791a2dSNicolas Ferre 	return false;
24374791a2dSNicolas Ferre }
24474791a2dSNicolas Ferre 
24574791a2dSNicolas Ferre 
24674791a2dSNicolas Ferre /*
247deec9ae3SHaavard Skinnemoen  * The debugfs stuff below is mostly optimized away when
248deec9ae3SHaavard Skinnemoen  * CONFIG_DEBUG_FS is not set.
249deec9ae3SHaavard Skinnemoen  */
250deec9ae3SHaavard Skinnemoen static int atmci_req_show(struct seq_file *s, void *v)
251deec9ae3SHaavard Skinnemoen {
252965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = s->private;
253965ebf33SHaavard Skinnemoen 	struct mmc_request	*mrq;
254deec9ae3SHaavard Skinnemoen 	struct mmc_command	*cmd;
255deec9ae3SHaavard Skinnemoen 	struct mmc_command	*stop;
256deec9ae3SHaavard Skinnemoen 	struct mmc_data		*data;
257deec9ae3SHaavard Skinnemoen 
258deec9ae3SHaavard Skinnemoen 	/* Make sure we get a consistent snapshot */
259965ebf33SHaavard Skinnemoen 	spin_lock_bh(&slot->host->lock);
260965ebf33SHaavard Skinnemoen 	mrq = slot->mrq;
261deec9ae3SHaavard Skinnemoen 
262deec9ae3SHaavard Skinnemoen 	if (mrq) {
263deec9ae3SHaavard Skinnemoen 		cmd = mrq->cmd;
264deec9ae3SHaavard Skinnemoen 		data = mrq->data;
265deec9ae3SHaavard Skinnemoen 		stop = mrq->stop;
266deec9ae3SHaavard Skinnemoen 
267deec9ae3SHaavard Skinnemoen 		if (cmd)
268deec9ae3SHaavard Skinnemoen 			seq_printf(s,
269deec9ae3SHaavard Skinnemoen 				"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
270deec9ae3SHaavard Skinnemoen 				cmd->opcode, cmd->arg, cmd->flags,
271deec9ae3SHaavard Skinnemoen 				cmd->resp[0], cmd->resp[1], cmd->resp[2],
272d586ebbbSNicolas Ferre 				cmd->resp[3], cmd->error);
273deec9ae3SHaavard Skinnemoen 		if (data)
274deec9ae3SHaavard Skinnemoen 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
275deec9ae3SHaavard Skinnemoen 				data->bytes_xfered, data->blocks,
276deec9ae3SHaavard Skinnemoen 				data->blksz, data->flags, data->error);
277deec9ae3SHaavard Skinnemoen 		if (stop)
278deec9ae3SHaavard Skinnemoen 			seq_printf(s,
279deec9ae3SHaavard Skinnemoen 				"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
280deec9ae3SHaavard Skinnemoen 				stop->opcode, stop->arg, stop->flags,
281deec9ae3SHaavard Skinnemoen 				stop->resp[0], stop->resp[1], stop->resp[2],
282d586ebbbSNicolas Ferre 				stop->resp[3], stop->error);
283deec9ae3SHaavard Skinnemoen 	}
284deec9ae3SHaavard Skinnemoen 
285965ebf33SHaavard Skinnemoen 	spin_unlock_bh(&slot->host->lock);
286deec9ae3SHaavard Skinnemoen 
287deec9ae3SHaavard Skinnemoen 	return 0;
288deec9ae3SHaavard Skinnemoen }
289deec9ae3SHaavard Skinnemoen 
290deec9ae3SHaavard Skinnemoen static int atmci_req_open(struct inode *inode, struct file *file)
291deec9ae3SHaavard Skinnemoen {
292deec9ae3SHaavard Skinnemoen 	return single_open(file, atmci_req_show, inode->i_private);
293deec9ae3SHaavard Skinnemoen }
294deec9ae3SHaavard Skinnemoen 
295deec9ae3SHaavard Skinnemoen static const struct file_operations atmci_req_fops = {
296deec9ae3SHaavard Skinnemoen 	.owner		= THIS_MODULE,
297deec9ae3SHaavard Skinnemoen 	.open		= atmci_req_open,
298deec9ae3SHaavard Skinnemoen 	.read		= seq_read,
299deec9ae3SHaavard Skinnemoen 	.llseek		= seq_lseek,
300deec9ae3SHaavard Skinnemoen 	.release	= single_release,
301deec9ae3SHaavard Skinnemoen };
302deec9ae3SHaavard Skinnemoen 
303deec9ae3SHaavard Skinnemoen static void atmci_show_status_reg(struct seq_file *s,
304deec9ae3SHaavard Skinnemoen 		const char *regname, u32 value)
305deec9ae3SHaavard Skinnemoen {
306deec9ae3SHaavard Skinnemoen 	static const char	*sr_bit[] = {
307deec9ae3SHaavard Skinnemoen 		[0]	= "CMDRDY",
308deec9ae3SHaavard Skinnemoen 		[1]	= "RXRDY",
309deec9ae3SHaavard Skinnemoen 		[2]	= "TXRDY",
310deec9ae3SHaavard Skinnemoen 		[3]	= "BLKE",
311deec9ae3SHaavard Skinnemoen 		[4]	= "DTIP",
312deec9ae3SHaavard Skinnemoen 		[5]	= "NOTBUSY",
31304d699c3SRob Emanuele 		[6]	= "ENDRX",
31404d699c3SRob Emanuele 		[7]	= "ENDTX",
315deec9ae3SHaavard Skinnemoen 		[8]	= "SDIOIRQA",
316deec9ae3SHaavard Skinnemoen 		[9]	= "SDIOIRQB",
31704d699c3SRob Emanuele 		[12]	= "SDIOWAIT",
31804d699c3SRob Emanuele 		[14]	= "RXBUFF",
31904d699c3SRob Emanuele 		[15]	= "TXBUFE",
320deec9ae3SHaavard Skinnemoen 		[16]	= "RINDE",
321deec9ae3SHaavard Skinnemoen 		[17]	= "RDIRE",
322deec9ae3SHaavard Skinnemoen 		[18]	= "RCRCE",
323deec9ae3SHaavard Skinnemoen 		[19]	= "RENDE",
324deec9ae3SHaavard Skinnemoen 		[20]	= "RTOE",
325deec9ae3SHaavard Skinnemoen 		[21]	= "DCRCE",
326deec9ae3SHaavard Skinnemoen 		[22]	= "DTOE",
32704d699c3SRob Emanuele 		[23]	= "CSTOE",
32804d699c3SRob Emanuele 		[24]	= "BLKOVRE",
32904d699c3SRob Emanuele 		[25]	= "DMADONE",
33004d699c3SRob Emanuele 		[26]	= "FIFOEMPTY",
33104d699c3SRob Emanuele 		[27]	= "XFRDONE",
332deec9ae3SHaavard Skinnemoen 		[30]	= "OVRE",
333deec9ae3SHaavard Skinnemoen 		[31]	= "UNRE",
334deec9ae3SHaavard Skinnemoen 	};
335deec9ae3SHaavard Skinnemoen 	unsigned int		i;
336deec9ae3SHaavard Skinnemoen 
337deec9ae3SHaavard Skinnemoen 	seq_printf(s, "%s:\t0x%08x", regname, value);
338deec9ae3SHaavard Skinnemoen 	for (i = 0; i < ARRAY_SIZE(sr_bit); i++) {
339deec9ae3SHaavard Skinnemoen 		if (value & (1 << i)) {
340deec9ae3SHaavard Skinnemoen 			if (sr_bit[i])
341deec9ae3SHaavard Skinnemoen 				seq_printf(s, " %s", sr_bit[i]);
342deec9ae3SHaavard Skinnemoen 			else
343deec9ae3SHaavard Skinnemoen 				seq_puts(s, " UNKNOWN");
344deec9ae3SHaavard Skinnemoen 		}
345deec9ae3SHaavard Skinnemoen 	}
346deec9ae3SHaavard Skinnemoen 	seq_putc(s, '\n');
347deec9ae3SHaavard Skinnemoen }
348deec9ae3SHaavard Skinnemoen 
349deec9ae3SHaavard Skinnemoen static int atmci_regs_show(struct seq_file *s, void *v)
350deec9ae3SHaavard Skinnemoen {
351deec9ae3SHaavard Skinnemoen 	struct atmel_mci	*host = s->private;
352deec9ae3SHaavard Skinnemoen 	u32			*buf;
353deec9ae3SHaavard Skinnemoen 
354deec9ae3SHaavard Skinnemoen 	buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL);
355deec9ae3SHaavard Skinnemoen 	if (!buf)
356deec9ae3SHaavard Skinnemoen 		return -ENOMEM;
357deec9ae3SHaavard Skinnemoen 
358965ebf33SHaavard Skinnemoen 	/*
359965ebf33SHaavard Skinnemoen 	 * Grab a more or less consistent snapshot. Note that we're
360965ebf33SHaavard Skinnemoen 	 * not disabling interrupts, so IMR and SR may not be
361965ebf33SHaavard Skinnemoen 	 * consistent.
362965ebf33SHaavard Skinnemoen 	 */
363965ebf33SHaavard Skinnemoen 	spin_lock_bh(&host->lock);
36487e60f2bSHaavard Skinnemoen 	clk_enable(host->mck);
365deec9ae3SHaavard Skinnemoen 	memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
36687e60f2bSHaavard Skinnemoen 	clk_disable(host->mck);
367965ebf33SHaavard Skinnemoen 	spin_unlock_bh(&host->lock);
368deec9ae3SHaavard Skinnemoen 
369deec9ae3SHaavard Skinnemoen 	seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
370deec9ae3SHaavard Skinnemoen 			buf[MCI_MR / 4],
371deec9ae3SHaavard Skinnemoen 			buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "",
372deec9ae3SHaavard Skinnemoen 			buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "",
373deec9ae3SHaavard Skinnemoen 			buf[MCI_MR / 4] & 0xff);
374deec9ae3SHaavard Skinnemoen 	seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]);
375deec9ae3SHaavard Skinnemoen 	seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]);
376deec9ae3SHaavard Skinnemoen 	seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]);
377deec9ae3SHaavard Skinnemoen 	seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n",
378deec9ae3SHaavard Skinnemoen 			buf[MCI_BLKR / 4],
379deec9ae3SHaavard Skinnemoen 			buf[MCI_BLKR / 4] & 0xffff,
380deec9ae3SHaavard Skinnemoen 			(buf[MCI_BLKR / 4] >> 16) & 0xffff);
38174791a2dSNicolas Ferre 	if (atmci_is_mci2())
38274791a2dSNicolas Ferre 		seq_printf(s, "CSTOR:\t0x%08x\n", buf[MCI_CSTOR / 4]);
383deec9ae3SHaavard Skinnemoen 
384deec9ae3SHaavard Skinnemoen 	/* Don't read RSPR and RDR; it will consume the data there */
385deec9ae3SHaavard Skinnemoen 
386deec9ae3SHaavard Skinnemoen 	atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]);
387deec9ae3SHaavard Skinnemoen 	atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]);
388deec9ae3SHaavard Skinnemoen 
38974791a2dSNicolas Ferre 	if (atmci_is_mci2()) {
39074791a2dSNicolas Ferre 		u32 val;
39174791a2dSNicolas Ferre 
39274791a2dSNicolas Ferre 		val = buf[MCI_DMA / 4];
39374791a2dSNicolas Ferre 		seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n",
39474791a2dSNicolas Ferre 				val, val & 3,
39574791a2dSNicolas Ferre 				((val >> 4) & 3) ?
39674791a2dSNicolas Ferre 					1 << (((val >> 4) & 3) + 1) : 1,
39774791a2dSNicolas Ferre 				val & MCI_DMAEN ? " DMAEN" : "");
39874791a2dSNicolas Ferre 
39974791a2dSNicolas Ferre 		val = buf[MCI_CFG / 4];
40074791a2dSNicolas Ferre 		seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n",
40174791a2dSNicolas Ferre 				val,
40274791a2dSNicolas Ferre 				val & MCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "",
40374791a2dSNicolas Ferre 				val & MCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "",
40474791a2dSNicolas Ferre 				val & MCI_CFG_HSMODE ? " HSMODE" : "",
40574791a2dSNicolas Ferre 				val & MCI_CFG_LSYNC ? " LSYNC" : "");
40674791a2dSNicolas Ferre 	}
40774791a2dSNicolas Ferre 
408b17339a1SHaavard Skinnemoen 	kfree(buf);
409b17339a1SHaavard Skinnemoen 
410deec9ae3SHaavard Skinnemoen 	return 0;
411deec9ae3SHaavard Skinnemoen }
412deec9ae3SHaavard Skinnemoen 
413deec9ae3SHaavard Skinnemoen static int atmci_regs_open(struct inode *inode, struct file *file)
414deec9ae3SHaavard Skinnemoen {
415deec9ae3SHaavard Skinnemoen 	return single_open(file, atmci_regs_show, inode->i_private);
416deec9ae3SHaavard Skinnemoen }
417deec9ae3SHaavard Skinnemoen 
418deec9ae3SHaavard Skinnemoen static const struct file_operations atmci_regs_fops = {
419deec9ae3SHaavard Skinnemoen 	.owner		= THIS_MODULE,
420deec9ae3SHaavard Skinnemoen 	.open		= atmci_regs_open,
421deec9ae3SHaavard Skinnemoen 	.read		= seq_read,
422deec9ae3SHaavard Skinnemoen 	.llseek		= seq_lseek,
423deec9ae3SHaavard Skinnemoen 	.release	= single_release,
424deec9ae3SHaavard Skinnemoen };
425deec9ae3SHaavard Skinnemoen 
426965ebf33SHaavard Skinnemoen static void atmci_init_debugfs(struct atmel_mci_slot *slot)
427deec9ae3SHaavard Skinnemoen {
428965ebf33SHaavard Skinnemoen 	struct mmc_host		*mmc = slot->mmc;
429965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = slot->host;
430deec9ae3SHaavard Skinnemoen 	struct dentry		*root;
431deec9ae3SHaavard Skinnemoen 	struct dentry		*node;
432deec9ae3SHaavard Skinnemoen 
433deec9ae3SHaavard Skinnemoen 	root = mmc->debugfs_root;
434deec9ae3SHaavard Skinnemoen 	if (!root)
435deec9ae3SHaavard Skinnemoen 		return;
436deec9ae3SHaavard Skinnemoen 
437deec9ae3SHaavard Skinnemoen 	node = debugfs_create_file("regs", S_IRUSR, root, host,
438deec9ae3SHaavard Skinnemoen 			&atmci_regs_fops);
439deec9ae3SHaavard Skinnemoen 	if (IS_ERR(node))
440deec9ae3SHaavard Skinnemoen 		return;
441deec9ae3SHaavard Skinnemoen 	if (!node)
442deec9ae3SHaavard Skinnemoen 		goto err;
443deec9ae3SHaavard Skinnemoen 
444965ebf33SHaavard Skinnemoen 	node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
445deec9ae3SHaavard Skinnemoen 	if (!node)
446deec9ae3SHaavard Skinnemoen 		goto err;
447deec9ae3SHaavard Skinnemoen 
448c06ad258SHaavard Skinnemoen 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
449c06ad258SHaavard Skinnemoen 	if (!node)
450c06ad258SHaavard Skinnemoen 		goto err;
451c06ad258SHaavard Skinnemoen 
452deec9ae3SHaavard Skinnemoen 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
453deec9ae3SHaavard Skinnemoen 				     (u32 *)&host->pending_events);
454deec9ae3SHaavard Skinnemoen 	if (!node)
455deec9ae3SHaavard Skinnemoen 		goto err;
456deec9ae3SHaavard Skinnemoen 
457deec9ae3SHaavard Skinnemoen 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
458deec9ae3SHaavard Skinnemoen 				     (u32 *)&host->completed_events);
459deec9ae3SHaavard Skinnemoen 	if (!node)
460deec9ae3SHaavard Skinnemoen 		goto err;
461deec9ae3SHaavard Skinnemoen 
462deec9ae3SHaavard Skinnemoen 	return;
463deec9ae3SHaavard Skinnemoen 
464deec9ae3SHaavard Skinnemoen err:
465965ebf33SHaavard Skinnemoen 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
466deec9ae3SHaavard Skinnemoen }
4677d2be074SHaavard Skinnemoen 
4687d2be074SHaavard Skinnemoen static inline unsigned int ns_to_clocks(struct atmel_mci *host,
4697d2be074SHaavard Skinnemoen 					unsigned int ns)
4707d2be074SHaavard Skinnemoen {
4717d2be074SHaavard Skinnemoen 	return (ns * (host->bus_hz / 1000000) + 999) / 1000;
4727d2be074SHaavard Skinnemoen }
4737d2be074SHaavard Skinnemoen 
4747d2be074SHaavard Skinnemoen static void atmci_set_timeout(struct atmel_mci *host,
475965ebf33SHaavard Skinnemoen 		struct atmel_mci_slot *slot, struct mmc_data *data)
4767d2be074SHaavard Skinnemoen {
4777d2be074SHaavard Skinnemoen 	static unsigned	dtomul_to_shift[] = {
4787d2be074SHaavard Skinnemoen 		0, 4, 7, 8, 10, 12, 16, 20
4797d2be074SHaavard Skinnemoen 	};
4807d2be074SHaavard Skinnemoen 	unsigned	timeout;
4817d2be074SHaavard Skinnemoen 	unsigned	dtocyc;
4827d2be074SHaavard Skinnemoen 	unsigned	dtomul;
4837d2be074SHaavard Skinnemoen 
4847d2be074SHaavard Skinnemoen 	timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks;
4857d2be074SHaavard Skinnemoen 
4867d2be074SHaavard Skinnemoen 	for (dtomul = 0; dtomul < 8; dtomul++) {
4877d2be074SHaavard Skinnemoen 		unsigned shift = dtomul_to_shift[dtomul];
4887d2be074SHaavard Skinnemoen 		dtocyc = (timeout + (1 << shift) - 1) >> shift;
4897d2be074SHaavard Skinnemoen 		if (dtocyc < 15)
4907d2be074SHaavard Skinnemoen 			break;
4917d2be074SHaavard Skinnemoen 	}
4927d2be074SHaavard Skinnemoen 
4937d2be074SHaavard Skinnemoen 	if (dtomul >= 8) {
4947d2be074SHaavard Skinnemoen 		dtomul = 7;
4957d2be074SHaavard Skinnemoen 		dtocyc = 15;
4967d2be074SHaavard Skinnemoen 	}
4977d2be074SHaavard Skinnemoen 
498965ebf33SHaavard Skinnemoen 	dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
4997d2be074SHaavard Skinnemoen 			dtocyc << dtomul_to_shift[dtomul]);
5007d2be074SHaavard Skinnemoen 	mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc)));
5017d2be074SHaavard Skinnemoen }
5027d2be074SHaavard Skinnemoen 
5037d2be074SHaavard Skinnemoen /*
5047d2be074SHaavard Skinnemoen  * Return mask with command flags to be enabled for this command.
5057d2be074SHaavard Skinnemoen  */
5067d2be074SHaavard Skinnemoen static u32 atmci_prepare_command(struct mmc_host *mmc,
5077d2be074SHaavard Skinnemoen 				 struct mmc_command *cmd)
5087d2be074SHaavard Skinnemoen {
5097d2be074SHaavard Skinnemoen 	struct mmc_data	*data;
5107d2be074SHaavard Skinnemoen 	u32		cmdr;
5117d2be074SHaavard Skinnemoen 
5127d2be074SHaavard Skinnemoen 	cmd->error = -EINPROGRESS;
5137d2be074SHaavard Skinnemoen 
5147d2be074SHaavard Skinnemoen 	cmdr = MCI_CMDR_CMDNB(cmd->opcode);
5157d2be074SHaavard Skinnemoen 
5167d2be074SHaavard Skinnemoen 	if (cmd->flags & MMC_RSP_PRESENT) {
5177d2be074SHaavard Skinnemoen 		if (cmd->flags & MMC_RSP_136)
5187d2be074SHaavard Skinnemoen 			cmdr |= MCI_CMDR_RSPTYP_136BIT;
5197d2be074SHaavard Skinnemoen 		else
5207d2be074SHaavard Skinnemoen 			cmdr |= MCI_CMDR_RSPTYP_48BIT;
5217d2be074SHaavard Skinnemoen 	}
5227d2be074SHaavard Skinnemoen 
5237d2be074SHaavard Skinnemoen 	/*
5247d2be074SHaavard Skinnemoen 	 * This should really be MAXLAT_5 for CMD2 and ACMD41, but
5257d2be074SHaavard Skinnemoen 	 * it's too difficult to determine whether this is an ACMD or
5267d2be074SHaavard Skinnemoen 	 * not. Better make it 64.
5277d2be074SHaavard Skinnemoen 	 */
5287d2be074SHaavard Skinnemoen 	cmdr |= MCI_CMDR_MAXLAT_64CYC;
5297d2be074SHaavard Skinnemoen 
5307d2be074SHaavard Skinnemoen 	if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
5317d2be074SHaavard Skinnemoen 		cmdr |= MCI_CMDR_OPDCMD;
5327d2be074SHaavard Skinnemoen 
5337d2be074SHaavard Skinnemoen 	data = cmd->data;
5347d2be074SHaavard Skinnemoen 	if (data) {
5357d2be074SHaavard Skinnemoen 		cmdr |= MCI_CMDR_START_XFER;
5362f1d7918SNicolas Ferre 
5372f1d7918SNicolas Ferre 		if (cmd->opcode == SD_IO_RW_EXTENDED) {
5382f1d7918SNicolas Ferre 			cmdr |= MCI_CMDR_SDIO_BLOCK;
5392f1d7918SNicolas Ferre 		} else {
5407d2be074SHaavard Skinnemoen 			if (data->flags & MMC_DATA_STREAM)
5417d2be074SHaavard Skinnemoen 				cmdr |= MCI_CMDR_STREAM;
5427d2be074SHaavard Skinnemoen 			else if (data->blocks > 1)
5437d2be074SHaavard Skinnemoen 				cmdr |= MCI_CMDR_MULTI_BLOCK;
5447d2be074SHaavard Skinnemoen 			else
5457d2be074SHaavard Skinnemoen 				cmdr |= MCI_CMDR_BLOCK;
5462f1d7918SNicolas Ferre 		}
5477d2be074SHaavard Skinnemoen 
5487d2be074SHaavard Skinnemoen 		if (data->flags & MMC_DATA_READ)
5497d2be074SHaavard Skinnemoen 			cmdr |= MCI_CMDR_TRDIR_READ;
5507d2be074SHaavard Skinnemoen 	}
5517d2be074SHaavard Skinnemoen 
5527d2be074SHaavard Skinnemoen 	return cmdr;
5537d2be074SHaavard Skinnemoen }
5547d2be074SHaavard Skinnemoen 
5557d2be074SHaavard Skinnemoen static void atmci_start_command(struct atmel_mci *host,
556965ebf33SHaavard Skinnemoen 		struct mmc_command *cmd, u32 cmd_flags)
5577d2be074SHaavard Skinnemoen {
5587d2be074SHaavard Skinnemoen 	WARN_ON(host->cmd);
5597d2be074SHaavard Skinnemoen 	host->cmd = cmd;
5607d2be074SHaavard Skinnemoen 
561965ebf33SHaavard Skinnemoen 	dev_vdbg(&host->pdev->dev,
5627d2be074SHaavard Skinnemoen 			"start command: ARGR=0x%08x CMDR=0x%08x\n",
5637d2be074SHaavard Skinnemoen 			cmd->arg, cmd_flags);
5647d2be074SHaavard Skinnemoen 
5657d2be074SHaavard Skinnemoen 	mci_writel(host, ARGR, cmd->arg);
5667d2be074SHaavard Skinnemoen 	mci_writel(host, CMDR, cmd_flags);
5677d2be074SHaavard Skinnemoen }
5687d2be074SHaavard Skinnemoen 
569965ebf33SHaavard Skinnemoen static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
5707d2be074SHaavard Skinnemoen {
5717d2be074SHaavard Skinnemoen 	atmci_start_command(host, data->stop, host->stop_cmdr);
5727d2be074SHaavard Skinnemoen 	mci_writel(host, IER, MCI_CMDRDY);
5737d2be074SHaavard Skinnemoen }
5747d2be074SHaavard Skinnemoen 
57565e8b083SHaavard Skinnemoen #ifdef CONFIG_MMC_ATMELMCI_DMA
57665e8b083SHaavard Skinnemoen static void atmci_dma_cleanup(struct atmel_mci *host)
57765e8b083SHaavard Skinnemoen {
57865e8b083SHaavard Skinnemoen 	struct mmc_data			*data = host->data;
57965e8b083SHaavard Skinnemoen 
580009a891bSNicolas Ferre 	if (data)
581266ac3f2SLinus Walleij 		dma_unmap_sg(host->dma.chan->device->dev,
582266ac3f2SLinus Walleij 			     data->sg, data->sg_len,
58365e8b083SHaavard Skinnemoen 			     ((data->flags & MMC_DATA_WRITE)
58465e8b083SHaavard Skinnemoen 			      ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
58565e8b083SHaavard Skinnemoen }
58665e8b083SHaavard Skinnemoen 
58765e8b083SHaavard Skinnemoen static void atmci_stop_dma(struct atmel_mci *host)
58865e8b083SHaavard Skinnemoen {
58965e8b083SHaavard Skinnemoen 	struct dma_chan *chan = host->data_chan;
59065e8b083SHaavard Skinnemoen 
59165e8b083SHaavard Skinnemoen 	if (chan) {
59205827630SLinus Walleij 	  chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
59365e8b083SHaavard Skinnemoen 		atmci_dma_cleanup(host);
59465e8b083SHaavard Skinnemoen 	} else {
59565e8b083SHaavard Skinnemoen 		/* Data transfer was stopped by the interrupt handler */
59665e8b083SHaavard Skinnemoen 		atmci_set_pending(host, EVENT_XFER_COMPLETE);
59765e8b083SHaavard Skinnemoen 		mci_writel(host, IER, MCI_NOTBUSY);
59865e8b083SHaavard Skinnemoen 	}
59965e8b083SHaavard Skinnemoen }
60065e8b083SHaavard Skinnemoen 
60165e8b083SHaavard Skinnemoen /* This function is called by the DMA driver from tasklet context. */
60265e8b083SHaavard Skinnemoen static void atmci_dma_complete(void *arg)
60365e8b083SHaavard Skinnemoen {
60465e8b083SHaavard Skinnemoen 	struct atmel_mci	*host = arg;
60565e8b083SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
60665e8b083SHaavard Skinnemoen 
60765e8b083SHaavard Skinnemoen 	dev_vdbg(&host->pdev->dev, "DMA complete\n");
60865e8b083SHaavard Skinnemoen 
60974791a2dSNicolas Ferre 	if (atmci_is_mci2())
61074791a2dSNicolas Ferre 		/* Disable DMA hardware handshaking on MCI */
61174791a2dSNicolas Ferre 		mci_writel(host, DMA, mci_readl(host, DMA) & ~MCI_DMAEN);
61274791a2dSNicolas Ferre 
61365e8b083SHaavard Skinnemoen 	atmci_dma_cleanup(host);
61465e8b083SHaavard Skinnemoen 
61565e8b083SHaavard Skinnemoen 	/*
61665e8b083SHaavard Skinnemoen 	 * If the card was removed, data will be NULL. No point trying
61765e8b083SHaavard Skinnemoen 	 * to send the stop command or waiting for NBUSY in this case.
61865e8b083SHaavard Skinnemoen 	 */
61965e8b083SHaavard Skinnemoen 	if (data) {
62065e8b083SHaavard Skinnemoen 		atmci_set_pending(host, EVENT_XFER_COMPLETE);
62165e8b083SHaavard Skinnemoen 		tasklet_schedule(&host->tasklet);
62265e8b083SHaavard Skinnemoen 
62365e8b083SHaavard Skinnemoen 		/*
62465e8b083SHaavard Skinnemoen 		 * Regardless of what the documentation says, we have
62565e8b083SHaavard Skinnemoen 		 * to wait for NOTBUSY even after block read
62665e8b083SHaavard Skinnemoen 		 * operations.
62765e8b083SHaavard Skinnemoen 		 *
62865e8b083SHaavard Skinnemoen 		 * When the DMA transfer is complete, the controller
62965e8b083SHaavard Skinnemoen 		 * may still be reading the CRC from the card, i.e.
63065e8b083SHaavard Skinnemoen 		 * the data transfer is still in progress and we
63165e8b083SHaavard Skinnemoen 		 * haven't seen all the potential error bits yet.
63265e8b083SHaavard Skinnemoen 		 *
63365e8b083SHaavard Skinnemoen 		 * The interrupt handler will schedule a different
63465e8b083SHaavard Skinnemoen 		 * tasklet to finish things up when the data transfer
63565e8b083SHaavard Skinnemoen 		 * is completely done.
63665e8b083SHaavard Skinnemoen 		 *
63765e8b083SHaavard Skinnemoen 		 * We may not complete the mmc request here anyway
63865e8b083SHaavard Skinnemoen 		 * because the mmc layer may call back and cause us to
63965e8b083SHaavard Skinnemoen 		 * violate the "don't submit new operations from the
64065e8b083SHaavard Skinnemoen 		 * completion callback" rule of the dma engine
64165e8b083SHaavard Skinnemoen 		 * framework.
64265e8b083SHaavard Skinnemoen 		 */
64365e8b083SHaavard Skinnemoen 		mci_writel(host, IER, MCI_NOTBUSY);
64465e8b083SHaavard Skinnemoen 	}
64565e8b083SHaavard Skinnemoen }
64665e8b083SHaavard Skinnemoen 
64765e8b083SHaavard Skinnemoen static int
64874791a2dSNicolas Ferre atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
64965e8b083SHaavard Skinnemoen {
65065e8b083SHaavard Skinnemoen 	struct dma_chan			*chan;
65165e8b083SHaavard Skinnemoen 	struct dma_async_tx_descriptor	*desc;
65265e8b083SHaavard Skinnemoen 	struct scatterlist		*sg;
65365e8b083SHaavard Skinnemoen 	unsigned int			i;
65465e8b083SHaavard Skinnemoen 	enum dma_data_direction		direction;
655657a77faSAtsushi Nemoto 	unsigned int			sglen;
65665e8b083SHaavard Skinnemoen 
65765e8b083SHaavard Skinnemoen 	/*
65865e8b083SHaavard Skinnemoen 	 * We don't do DMA on "complex" transfers, i.e. with
65965e8b083SHaavard Skinnemoen 	 * non-word-aligned buffers or lengths. Also, we don't bother
66065e8b083SHaavard Skinnemoen 	 * with all the DMA setup overhead for short transfers.
66165e8b083SHaavard Skinnemoen 	 */
66265e8b083SHaavard Skinnemoen 	if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
66365e8b083SHaavard Skinnemoen 		return -EINVAL;
66465e8b083SHaavard Skinnemoen 	if (data->blksz & 3)
66565e8b083SHaavard Skinnemoen 		return -EINVAL;
66665e8b083SHaavard Skinnemoen 
66765e8b083SHaavard Skinnemoen 	for_each_sg(data->sg, sg, data->sg_len, i) {
66865e8b083SHaavard Skinnemoen 		if (sg->offset & 3 || sg->length & 3)
66965e8b083SHaavard Skinnemoen 			return -EINVAL;
67065e8b083SHaavard Skinnemoen 	}
67165e8b083SHaavard Skinnemoen 
67265e8b083SHaavard Skinnemoen 	/* If we don't have a channel, we can't do DMA */
67365e8b083SHaavard Skinnemoen 	chan = host->dma.chan;
6746f49a57aSDan Williams 	if (chan)
67565e8b083SHaavard Skinnemoen 		host->data_chan = chan;
67665e8b083SHaavard Skinnemoen 
67765e8b083SHaavard Skinnemoen 	if (!chan)
67865e8b083SHaavard Skinnemoen 		return -ENODEV;
67965e8b083SHaavard Skinnemoen 
68074791a2dSNicolas Ferre 	if (atmci_is_mci2())
68174791a2dSNicolas Ferre 		mci_writel(host, DMA, MCI_DMA_CHKSIZE(3) | MCI_DMAEN);
68274791a2dSNicolas Ferre 
68365e8b083SHaavard Skinnemoen 	if (data->flags & MMC_DATA_READ)
68465e8b083SHaavard Skinnemoen 		direction = DMA_FROM_DEVICE;
68565e8b083SHaavard Skinnemoen 	else
68665e8b083SHaavard Skinnemoen 		direction = DMA_TO_DEVICE;
68765e8b083SHaavard Skinnemoen 
688266ac3f2SLinus Walleij 	sglen = dma_map_sg(chan->device->dev, data->sg,
689266ac3f2SLinus Walleij 			   data->sg_len, direction);
690657a77faSAtsushi Nemoto 	if (sglen != data->sg_len)
691657a77faSAtsushi Nemoto 		goto unmap_exit;
69265e8b083SHaavard Skinnemoen 	desc = chan->device->device_prep_slave_sg(chan,
69365e8b083SHaavard Skinnemoen 			data->sg, data->sg_len, direction,
69465e8b083SHaavard Skinnemoen 			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
69565e8b083SHaavard Skinnemoen 	if (!desc)
696657a77faSAtsushi Nemoto 		goto unmap_exit;
69765e8b083SHaavard Skinnemoen 
69865e8b083SHaavard Skinnemoen 	host->dma.data_desc = desc;
69965e8b083SHaavard Skinnemoen 	desc->callback = atmci_dma_complete;
70065e8b083SHaavard Skinnemoen 	desc->callback_param = host;
70165e8b083SHaavard Skinnemoen 
70265e8b083SHaavard Skinnemoen 	return 0;
703657a77faSAtsushi Nemoto unmap_exit:
704266ac3f2SLinus Walleij 	dma_unmap_sg(chan->device->dev, data->sg, sglen, direction);
705657a77faSAtsushi Nemoto 	return -ENOMEM;
70665e8b083SHaavard Skinnemoen }
70765e8b083SHaavard Skinnemoen 
70874791a2dSNicolas Ferre static void atmci_submit_data(struct atmel_mci *host)
70974791a2dSNicolas Ferre {
71074791a2dSNicolas Ferre 	struct dma_chan			*chan = host->data_chan;
71174791a2dSNicolas Ferre 	struct dma_async_tx_descriptor	*desc = host->dma.data_desc;
71274791a2dSNicolas Ferre 
71374791a2dSNicolas Ferre 	if (chan) {
71474791a2dSNicolas Ferre 		desc->tx_submit(desc);
71574791a2dSNicolas Ferre 		chan->device->device_issue_pending(chan);
71674791a2dSNicolas Ferre 	}
71774791a2dSNicolas Ferre }
71874791a2dSNicolas Ferre 
71965e8b083SHaavard Skinnemoen #else /* CONFIG_MMC_ATMELMCI_DMA */
72065e8b083SHaavard Skinnemoen 
72174791a2dSNicolas Ferre static int atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
72265e8b083SHaavard Skinnemoen {
72365e8b083SHaavard Skinnemoen 	return -ENOSYS;
72465e8b083SHaavard Skinnemoen }
72565e8b083SHaavard Skinnemoen 
72674791a2dSNicolas Ferre static void atmci_submit_data(struct atmel_mci *host) {}
72774791a2dSNicolas Ferre 
72865e8b083SHaavard Skinnemoen static void atmci_stop_dma(struct atmel_mci *host)
72965e8b083SHaavard Skinnemoen {
73065e8b083SHaavard Skinnemoen 	/* Data transfer was stopped by the interrupt handler */
73165e8b083SHaavard Skinnemoen 	atmci_set_pending(host, EVENT_XFER_COMPLETE);
73265e8b083SHaavard Skinnemoen 	mci_writel(host, IER, MCI_NOTBUSY);
73365e8b083SHaavard Skinnemoen }
73465e8b083SHaavard Skinnemoen 
73565e8b083SHaavard Skinnemoen #endif /* CONFIG_MMC_ATMELMCI_DMA */
73665e8b083SHaavard Skinnemoen 
7377d2be074SHaavard Skinnemoen /*
7387d2be074SHaavard Skinnemoen  * Returns a mask of interrupt flags to be enabled after the whole
7397d2be074SHaavard Skinnemoen  * request has been prepared.
7407d2be074SHaavard Skinnemoen  */
74174791a2dSNicolas Ferre static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
7427d2be074SHaavard Skinnemoen {
7437d2be074SHaavard Skinnemoen 	u32 iflags;
7447d2be074SHaavard Skinnemoen 
7457d2be074SHaavard Skinnemoen 	data->error = -EINPROGRESS;
7467d2be074SHaavard Skinnemoen 
7477d2be074SHaavard Skinnemoen 	WARN_ON(host->data);
7487d2be074SHaavard Skinnemoen 	host->sg = NULL;
7497d2be074SHaavard Skinnemoen 	host->data = data;
7507d2be074SHaavard Skinnemoen 
7517d2be074SHaavard Skinnemoen 	iflags = ATMCI_DATA_ERROR_FLAGS;
75274791a2dSNicolas Ferre 	if (atmci_prepare_data_dma(host, data)) {
75365e8b083SHaavard Skinnemoen 		host->data_chan = NULL;
754965ebf33SHaavard Skinnemoen 
755965ebf33SHaavard Skinnemoen 		/*
756965ebf33SHaavard Skinnemoen 		 * Errata: MMC data write operation with less than 12
757965ebf33SHaavard Skinnemoen 		 * bytes is impossible.
758965ebf33SHaavard Skinnemoen 		 *
759965ebf33SHaavard Skinnemoen 		 * Errata: MCI Transmit Data Register (TDR) FIFO
760965ebf33SHaavard Skinnemoen 		 * corruption when length is not multiple of 4.
761965ebf33SHaavard Skinnemoen 		 */
762965ebf33SHaavard Skinnemoen 		if (data->blocks * data->blksz < 12
763965ebf33SHaavard Skinnemoen 				|| (data->blocks * data->blksz) & 3)
764965ebf33SHaavard Skinnemoen 			host->need_reset = true;
765965ebf33SHaavard Skinnemoen 
7667d2be074SHaavard Skinnemoen 		host->sg = data->sg;
7677d2be074SHaavard Skinnemoen 		host->pio_offset = 0;
7687d2be074SHaavard Skinnemoen 		if (data->flags & MMC_DATA_READ)
7697d2be074SHaavard Skinnemoen 			iflags |= MCI_RXRDY;
7707d2be074SHaavard Skinnemoen 		else
7717d2be074SHaavard Skinnemoen 			iflags |= MCI_TXRDY;
77265e8b083SHaavard Skinnemoen 	}
7737d2be074SHaavard Skinnemoen 
7747d2be074SHaavard Skinnemoen 	return iflags;
7757d2be074SHaavard Skinnemoen }
7767d2be074SHaavard Skinnemoen 
777965ebf33SHaavard Skinnemoen static void atmci_start_request(struct atmel_mci *host,
778965ebf33SHaavard Skinnemoen 		struct atmel_mci_slot *slot)
7797d2be074SHaavard Skinnemoen {
780965ebf33SHaavard Skinnemoen 	struct mmc_request	*mrq;
7817d2be074SHaavard Skinnemoen 	struct mmc_command	*cmd;
782965ebf33SHaavard Skinnemoen 	struct mmc_data		*data;
7837d2be074SHaavard Skinnemoen 	u32			iflags;
784965ebf33SHaavard Skinnemoen 	u32			cmdflags;
785965ebf33SHaavard Skinnemoen 
786965ebf33SHaavard Skinnemoen 	mrq = slot->mrq;
787965ebf33SHaavard Skinnemoen 	host->cur_slot = slot;
788965ebf33SHaavard Skinnemoen 	host->mrq = mrq;
789965ebf33SHaavard Skinnemoen 
790965ebf33SHaavard Skinnemoen 	host->pending_events = 0;
791965ebf33SHaavard Skinnemoen 	host->completed_events = 0;
792ca55f46eSHaavard Skinnemoen 	host->data_status = 0;
793965ebf33SHaavard Skinnemoen 
794965ebf33SHaavard Skinnemoen 	if (host->need_reset) {
795965ebf33SHaavard Skinnemoen 		mci_writel(host, CR, MCI_CR_SWRST);
796965ebf33SHaavard Skinnemoen 		mci_writel(host, CR, MCI_CR_MCIEN);
797965ebf33SHaavard Skinnemoen 		mci_writel(host, MR, host->mode_reg);
79874791a2dSNicolas Ferre 		if (atmci_is_mci2())
79974791a2dSNicolas Ferre 			mci_writel(host, CFG, host->cfg_reg);
800965ebf33SHaavard Skinnemoen 		host->need_reset = false;
801965ebf33SHaavard Skinnemoen 	}
802965ebf33SHaavard Skinnemoen 	mci_writel(host, SDCR, slot->sdc_reg);
8037d2be074SHaavard Skinnemoen 
8047d2be074SHaavard Skinnemoen 	iflags = mci_readl(host, IMR);
80588ff82edSAnders Grahn 	if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB))
806965ebf33SHaavard Skinnemoen 		dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
807965ebf33SHaavard Skinnemoen 				iflags);
8087d2be074SHaavard Skinnemoen 
809965ebf33SHaavard Skinnemoen 	if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
810965ebf33SHaavard Skinnemoen 		/* Send init sequence (74 clock cycles) */
811965ebf33SHaavard Skinnemoen 		mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
812965ebf33SHaavard Skinnemoen 		while (!(mci_readl(host, SR) & MCI_CMDRDY))
813965ebf33SHaavard Skinnemoen 			cpu_relax();
8147d2be074SHaavard Skinnemoen 	}
81574791a2dSNicolas Ferre 	iflags = 0;
8167d2be074SHaavard Skinnemoen 	data = mrq->data;
8177d2be074SHaavard Skinnemoen 	if (data) {
818965ebf33SHaavard Skinnemoen 		atmci_set_timeout(host, slot, data);
819a252e3e3SHaavard Skinnemoen 
820a252e3e3SHaavard Skinnemoen 		/* Must set block count/size before sending command */
821a252e3e3SHaavard Skinnemoen 		mci_writel(host, BLKR, MCI_BCNT(data->blocks)
822a252e3e3SHaavard Skinnemoen 				| MCI_BLKLEN(data->blksz));
823965ebf33SHaavard Skinnemoen 		dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
824965ebf33SHaavard Skinnemoen 			MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
82574791a2dSNicolas Ferre 
82674791a2dSNicolas Ferre 		iflags |= atmci_prepare_data(host, data);
8277d2be074SHaavard Skinnemoen 	}
8287d2be074SHaavard Skinnemoen 
82974791a2dSNicolas Ferre 	iflags |= MCI_CMDRDY;
8307d2be074SHaavard Skinnemoen 	cmd = mrq->cmd;
831965ebf33SHaavard Skinnemoen 	cmdflags = atmci_prepare_command(slot->mmc, cmd);
8327d2be074SHaavard Skinnemoen 	atmci_start_command(host, cmd, cmdflags);
8337d2be074SHaavard Skinnemoen 
8347d2be074SHaavard Skinnemoen 	if (data)
83574791a2dSNicolas Ferre 		atmci_submit_data(host);
8367d2be074SHaavard Skinnemoen 
8377d2be074SHaavard Skinnemoen 	if (mrq->stop) {
838965ebf33SHaavard Skinnemoen 		host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
8397d2be074SHaavard Skinnemoen 		host->stop_cmdr |= MCI_CMDR_STOP_XFER;
8407d2be074SHaavard Skinnemoen 		if (!(data->flags & MMC_DATA_WRITE))
8417d2be074SHaavard Skinnemoen 			host->stop_cmdr |= MCI_CMDR_TRDIR_READ;
8427d2be074SHaavard Skinnemoen 		if (data->flags & MMC_DATA_STREAM)
8437d2be074SHaavard Skinnemoen 			host->stop_cmdr |= MCI_CMDR_STREAM;
8447d2be074SHaavard Skinnemoen 		else
8457d2be074SHaavard Skinnemoen 			host->stop_cmdr |= MCI_CMDR_MULTI_BLOCK;
8467d2be074SHaavard Skinnemoen 	}
8477d2be074SHaavard Skinnemoen 
8487d2be074SHaavard Skinnemoen 	/*
8497d2be074SHaavard Skinnemoen 	 * We could have enabled interrupts earlier, but I suspect
8507d2be074SHaavard Skinnemoen 	 * that would open up a nice can of interesting race
8517d2be074SHaavard Skinnemoen 	 * conditions (e.g. command and data complete, but stop not
8527d2be074SHaavard Skinnemoen 	 * prepared yet.)
8537d2be074SHaavard Skinnemoen 	 */
8547d2be074SHaavard Skinnemoen 	mci_writel(host, IER, iflags);
855965ebf33SHaavard Skinnemoen }
8567d2be074SHaavard Skinnemoen 
857965ebf33SHaavard Skinnemoen static void atmci_queue_request(struct atmel_mci *host,
858965ebf33SHaavard Skinnemoen 		struct atmel_mci_slot *slot, struct mmc_request *mrq)
859965ebf33SHaavard Skinnemoen {
860965ebf33SHaavard Skinnemoen 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
861965ebf33SHaavard Skinnemoen 			host->state);
862965ebf33SHaavard Skinnemoen 
863965ebf33SHaavard Skinnemoen 	spin_lock_bh(&host->lock);
864965ebf33SHaavard Skinnemoen 	slot->mrq = mrq;
865965ebf33SHaavard Skinnemoen 	if (host->state == STATE_IDLE) {
866965ebf33SHaavard Skinnemoen 		host->state = STATE_SENDING_CMD;
867965ebf33SHaavard Skinnemoen 		atmci_start_request(host, slot);
868965ebf33SHaavard Skinnemoen 	} else {
869965ebf33SHaavard Skinnemoen 		list_add_tail(&slot->queue_node, &host->queue);
870965ebf33SHaavard Skinnemoen 	}
871965ebf33SHaavard Skinnemoen 	spin_unlock_bh(&host->lock);
872965ebf33SHaavard Skinnemoen }
873965ebf33SHaavard Skinnemoen 
874965ebf33SHaavard Skinnemoen static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
875965ebf33SHaavard Skinnemoen {
876965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
877965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = slot->host;
878965ebf33SHaavard Skinnemoen 	struct mmc_data		*data;
879965ebf33SHaavard Skinnemoen 
880965ebf33SHaavard Skinnemoen 	WARN_ON(slot->mrq);
881965ebf33SHaavard Skinnemoen 
882965ebf33SHaavard Skinnemoen 	/*
883965ebf33SHaavard Skinnemoen 	 * We may "know" the card is gone even though there's still an
884965ebf33SHaavard Skinnemoen 	 * electrical connection. If so, we really need to communicate
885965ebf33SHaavard Skinnemoen 	 * this to the MMC core since there won't be any more
886965ebf33SHaavard Skinnemoen 	 * interrupts as the card is completely removed. Otherwise,
887965ebf33SHaavard Skinnemoen 	 * the MMC core might believe the card is still there even
888965ebf33SHaavard Skinnemoen 	 * though the card was just removed very slowly.
889965ebf33SHaavard Skinnemoen 	 */
890965ebf33SHaavard Skinnemoen 	if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
891965ebf33SHaavard Skinnemoen 		mrq->cmd->error = -ENOMEDIUM;
892965ebf33SHaavard Skinnemoen 		mmc_request_done(mmc, mrq);
8937d2be074SHaavard Skinnemoen 		return;
894965ebf33SHaavard Skinnemoen 	}
8957d2be074SHaavard Skinnemoen 
896965ebf33SHaavard Skinnemoen 	/* We don't support multiple blocks of weird lengths. */
897965ebf33SHaavard Skinnemoen 	data = mrq->data;
898965ebf33SHaavard Skinnemoen 	if (data && data->blocks > 1 && data->blksz & 3) {
8997d2be074SHaavard Skinnemoen 		mrq->cmd->error = -EINVAL;
9007d2be074SHaavard Skinnemoen 		mmc_request_done(mmc, mrq);
9017d2be074SHaavard Skinnemoen 	}
9027d2be074SHaavard Skinnemoen 
903965ebf33SHaavard Skinnemoen 	atmci_queue_request(host, slot, mrq);
904965ebf33SHaavard Skinnemoen }
905965ebf33SHaavard Skinnemoen 
9067d2be074SHaavard Skinnemoen static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
9077d2be074SHaavard Skinnemoen {
908965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
909965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = slot->host;
910965ebf33SHaavard Skinnemoen 	unsigned int		i;
9117d2be074SHaavard Skinnemoen 
912965ebf33SHaavard Skinnemoen 	slot->sdc_reg &= ~MCI_SDCBUS_MASK;
913945533b5SHaavard Skinnemoen 	switch (ios->bus_width) {
914945533b5SHaavard Skinnemoen 	case MMC_BUS_WIDTH_1:
915965ebf33SHaavard Skinnemoen 		slot->sdc_reg |= MCI_SDCBUS_1BIT;
916945533b5SHaavard Skinnemoen 		break;
917945533b5SHaavard Skinnemoen 	case MMC_BUS_WIDTH_4:
91832ab83a5SHans-Christian Egtvedt 		slot->sdc_reg |= MCI_SDCBUS_4BIT;
919945533b5SHaavard Skinnemoen 		break;
920945533b5SHaavard Skinnemoen 	}
921945533b5SHaavard Skinnemoen 
9227d2be074SHaavard Skinnemoen 	if (ios->clock) {
923965ebf33SHaavard Skinnemoen 		unsigned int clock_min = ~0U;
9247d2be074SHaavard Skinnemoen 		u32 clkdiv;
9257d2be074SHaavard Skinnemoen 
926965ebf33SHaavard Skinnemoen 		spin_lock_bh(&host->lock);
927965ebf33SHaavard Skinnemoen 		if (!host->mode_reg) {
928945533b5SHaavard Skinnemoen 			clk_enable(host->mck);
929965ebf33SHaavard Skinnemoen 			mci_writel(host, CR, MCI_CR_SWRST);
930965ebf33SHaavard Skinnemoen 			mci_writel(host, CR, MCI_CR_MCIEN);
93174791a2dSNicolas Ferre 			if (atmci_is_mci2())
93274791a2dSNicolas Ferre 				mci_writel(host, CFG, host->cfg_reg);
933965ebf33SHaavard Skinnemoen 		}
934945533b5SHaavard Skinnemoen 
935965ebf33SHaavard Skinnemoen 		/*
936965ebf33SHaavard Skinnemoen 		 * Use mirror of ios->clock to prevent race with mmc
937965ebf33SHaavard Skinnemoen 		 * core ios update when finding the minimum.
938965ebf33SHaavard Skinnemoen 		 */
939965ebf33SHaavard Skinnemoen 		slot->clock = ios->clock;
940965ebf33SHaavard Skinnemoen 		for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
941965ebf33SHaavard Skinnemoen 			if (host->slot[i] && host->slot[i]->clock
942965ebf33SHaavard Skinnemoen 					&& host->slot[i]->clock < clock_min)
943965ebf33SHaavard Skinnemoen 				clock_min = host->slot[i]->clock;
944965ebf33SHaavard Skinnemoen 		}
945965ebf33SHaavard Skinnemoen 
946965ebf33SHaavard Skinnemoen 		/* Calculate clock divider */
947965ebf33SHaavard Skinnemoen 		clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
9487d2be074SHaavard Skinnemoen 		if (clkdiv > 255) {
9497d2be074SHaavard Skinnemoen 			dev_warn(&mmc->class_dev,
9507d2be074SHaavard Skinnemoen 				"clock %u too slow; using %lu\n",
951965ebf33SHaavard Skinnemoen 				clock_min, host->bus_hz / (2 * 256));
9527d2be074SHaavard Skinnemoen 			clkdiv = 255;
9537d2be074SHaavard Skinnemoen 		}
9547d2be074SHaavard Skinnemoen 
95504d699c3SRob Emanuele 		host->mode_reg = MCI_MR_CLKDIV(clkdiv);
95604d699c3SRob Emanuele 
957965ebf33SHaavard Skinnemoen 		/*
958965ebf33SHaavard Skinnemoen 		 * WRPROOF and RDPROOF prevent overruns/underruns by
959965ebf33SHaavard Skinnemoen 		 * stopping the clock when the FIFO is full/empty.
960965ebf33SHaavard Skinnemoen 		 * This state is not expected to last for long.
961965ebf33SHaavard Skinnemoen 		 */
96204d699c3SRob Emanuele 		if (mci_has_rwproof())
96304d699c3SRob Emanuele 			host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF);
9647d2be074SHaavard Skinnemoen 
96599ddffd8SNicolas Ferre 		if (atmci_is_mci2()) {
96699ddffd8SNicolas Ferre 			/* setup High Speed mode in relation with card capacity */
96799ddffd8SNicolas Ferre 			if (ios->timing == MMC_TIMING_SD_HS)
96899ddffd8SNicolas Ferre 				host->cfg_reg |= MCI_CFG_HSMODE;
969965ebf33SHaavard Skinnemoen 			else
97099ddffd8SNicolas Ferre 				host->cfg_reg &= ~MCI_CFG_HSMODE;
97199ddffd8SNicolas Ferre 		}
97299ddffd8SNicolas Ferre 
97399ddffd8SNicolas Ferre 		if (list_empty(&host->queue)) {
97499ddffd8SNicolas Ferre 			mci_writel(host, MR, host->mode_reg);
97599ddffd8SNicolas Ferre 			if (atmci_is_mci2())
97699ddffd8SNicolas Ferre 				mci_writel(host, CFG, host->cfg_reg);
97799ddffd8SNicolas Ferre 		} else {
978965ebf33SHaavard Skinnemoen 			host->need_clock_update = true;
97999ddffd8SNicolas Ferre 		}
980965ebf33SHaavard Skinnemoen 
981965ebf33SHaavard Skinnemoen 		spin_unlock_bh(&host->lock);
982945533b5SHaavard Skinnemoen 	} else {
983965ebf33SHaavard Skinnemoen 		bool any_slot_active = false;
984965ebf33SHaavard Skinnemoen 
985965ebf33SHaavard Skinnemoen 		spin_lock_bh(&host->lock);
986965ebf33SHaavard Skinnemoen 		slot->clock = 0;
987965ebf33SHaavard Skinnemoen 		for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
988965ebf33SHaavard Skinnemoen 			if (host->slot[i] && host->slot[i]->clock) {
989965ebf33SHaavard Skinnemoen 				any_slot_active = true;
990965ebf33SHaavard Skinnemoen 				break;
991965ebf33SHaavard Skinnemoen 			}
992965ebf33SHaavard Skinnemoen 		}
993965ebf33SHaavard Skinnemoen 		if (!any_slot_active) {
994945533b5SHaavard Skinnemoen 			mci_writel(host, CR, MCI_CR_MCIDIS);
995945533b5SHaavard Skinnemoen 			if (host->mode_reg) {
996945533b5SHaavard Skinnemoen 				mci_readl(host, MR);
997945533b5SHaavard Skinnemoen 				clk_disable(host->mck);
998945533b5SHaavard Skinnemoen 			}
999945533b5SHaavard Skinnemoen 			host->mode_reg = 0;
10007d2be074SHaavard Skinnemoen 		}
1001965ebf33SHaavard Skinnemoen 		spin_unlock_bh(&host->lock);
1002965ebf33SHaavard Skinnemoen 	}
10037d2be074SHaavard Skinnemoen 
10047d2be074SHaavard Skinnemoen 	switch (ios->power_mode) {
1005965ebf33SHaavard Skinnemoen 	case MMC_POWER_UP:
1006965ebf33SHaavard Skinnemoen 		set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
1007965ebf33SHaavard Skinnemoen 		break;
10087d2be074SHaavard Skinnemoen 	default:
10097d2be074SHaavard Skinnemoen 		/*
10107d2be074SHaavard Skinnemoen 		 * TODO: None of the currently available AVR32-based
10117d2be074SHaavard Skinnemoen 		 * boards allow MMC power to be turned off. Implement
10127d2be074SHaavard Skinnemoen 		 * power control when this can be tested properly.
1013965ebf33SHaavard Skinnemoen 		 *
1014965ebf33SHaavard Skinnemoen 		 * We also need to hook this into the clock management
1015965ebf33SHaavard Skinnemoen 		 * somehow so that newly inserted cards aren't
1016965ebf33SHaavard Skinnemoen 		 * subjected to a fast clock before we have a chance
1017965ebf33SHaavard Skinnemoen 		 * to figure out what the maximum rate is. Currently,
1018965ebf33SHaavard Skinnemoen 		 * there's no way to avoid this, and there never will
1019965ebf33SHaavard Skinnemoen 		 * be for boards that don't support power control.
10207d2be074SHaavard Skinnemoen 		 */
10217d2be074SHaavard Skinnemoen 		break;
10227d2be074SHaavard Skinnemoen 	}
10237d2be074SHaavard Skinnemoen }
10247d2be074SHaavard Skinnemoen 
10257d2be074SHaavard Skinnemoen static int atmci_get_ro(struct mmc_host *mmc)
10267d2be074SHaavard Skinnemoen {
1027965ebf33SHaavard Skinnemoen 	int			read_only = -ENOSYS;
1028965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
10297d2be074SHaavard Skinnemoen 
1030965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->wp_pin)) {
1031965ebf33SHaavard Skinnemoen 		read_only = gpio_get_value(slot->wp_pin);
10327d2be074SHaavard Skinnemoen 		dev_dbg(&mmc->class_dev, "card is %s\n",
10337d2be074SHaavard Skinnemoen 				read_only ? "read-only" : "read-write");
10347d2be074SHaavard Skinnemoen 	}
10357d2be074SHaavard Skinnemoen 
10367d2be074SHaavard Skinnemoen 	return read_only;
10377d2be074SHaavard Skinnemoen }
10387d2be074SHaavard Skinnemoen 
1039965ebf33SHaavard Skinnemoen static int atmci_get_cd(struct mmc_host *mmc)
1040965ebf33SHaavard Skinnemoen {
1041965ebf33SHaavard Skinnemoen 	int			present = -ENOSYS;
1042965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
1043965ebf33SHaavard Skinnemoen 
1044965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
10451c1452beSJonas Larsson 		present = !(gpio_get_value(slot->detect_pin) ^
10461c1452beSJonas Larsson 			    slot->detect_is_active_high);
1047965ebf33SHaavard Skinnemoen 		dev_dbg(&mmc->class_dev, "card is %spresent\n",
1048965ebf33SHaavard Skinnemoen 				present ? "" : "not ");
1049965ebf33SHaavard Skinnemoen 	}
1050965ebf33SHaavard Skinnemoen 
1051965ebf33SHaavard Skinnemoen 	return present;
1052965ebf33SHaavard Skinnemoen }
1053965ebf33SHaavard Skinnemoen 
105488ff82edSAnders Grahn static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
105588ff82edSAnders Grahn {
105688ff82edSAnders Grahn 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
105788ff82edSAnders Grahn 	struct atmel_mci	*host = slot->host;
105888ff82edSAnders Grahn 
105988ff82edSAnders Grahn 	if (enable)
106088ff82edSAnders Grahn 		mci_writel(host, IER, slot->sdio_irq);
106188ff82edSAnders Grahn 	else
106288ff82edSAnders Grahn 		mci_writel(host, IDR, slot->sdio_irq);
106388ff82edSAnders Grahn }
106488ff82edSAnders Grahn 
1065965ebf33SHaavard Skinnemoen static const struct mmc_host_ops atmci_ops = {
10667d2be074SHaavard Skinnemoen 	.request	= atmci_request,
10677d2be074SHaavard Skinnemoen 	.set_ios	= atmci_set_ios,
10687d2be074SHaavard Skinnemoen 	.get_ro		= atmci_get_ro,
1069965ebf33SHaavard Skinnemoen 	.get_cd		= atmci_get_cd,
107088ff82edSAnders Grahn 	.enable_sdio_irq = atmci_enable_sdio_irq,
10717d2be074SHaavard Skinnemoen };
10727d2be074SHaavard Skinnemoen 
1073965ebf33SHaavard Skinnemoen /* Called with host->lock held */
1074965ebf33SHaavard Skinnemoen static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
1075965ebf33SHaavard Skinnemoen 	__releases(&host->lock)
1076965ebf33SHaavard Skinnemoen 	__acquires(&host->lock)
1077965ebf33SHaavard Skinnemoen {
1078965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = NULL;
1079965ebf33SHaavard Skinnemoen 	struct mmc_host		*prev_mmc = host->cur_slot->mmc;
1080965ebf33SHaavard Skinnemoen 
1081965ebf33SHaavard Skinnemoen 	WARN_ON(host->cmd || host->data);
1082965ebf33SHaavard Skinnemoen 
1083965ebf33SHaavard Skinnemoen 	/*
1084965ebf33SHaavard Skinnemoen 	 * Update the MMC clock rate if necessary. This may be
1085965ebf33SHaavard Skinnemoen 	 * necessary if set_ios() is called when a different slot is
1086965ebf33SHaavard Skinnemoen 	 * busy transfering data.
1087965ebf33SHaavard Skinnemoen 	 */
108899ddffd8SNicolas Ferre 	if (host->need_clock_update) {
1089965ebf33SHaavard Skinnemoen 		mci_writel(host, MR, host->mode_reg);
109099ddffd8SNicolas Ferre 		if (atmci_is_mci2())
109199ddffd8SNicolas Ferre 			mci_writel(host, CFG, host->cfg_reg);
109299ddffd8SNicolas Ferre 	}
1093965ebf33SHaavard Skinnemoen 
1094965ebf33SHaavard Skinnemoen 	host->cur_slot->mrq = NULL;
1095965ebf33SHaavard Skinnemoen 	host->mrq = NULL;
1096965ebf33SHaavard Skinnemoen 	if (!list_empty(&host->queue)) {
1097965ebf33SHaavard Skinnemoen 		slot = list_entry(host->queue.next,
1098965ebf33SHaavard Skinnemoen 				struct atmel_mci_slot, queue_node);
1099965ebf33SHaavard Skinnemoen 		list_del(&slot->queue_node);
1100965ebf33SHaavard Skinnemoen 		dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
1101965ebf33SHaavard Skinnemoen 				mmc_hostname(slot->mmc));
1102965ebf33SHaavard Skinnemoen 		host->state = STATE_SENDING_CMD;
1103965ebf33SHaavard Skinnemoen 		atmci_start_request(host, slot);
1104965ebf33SHaavard Skinnemoen 	} else {
1105965ebf33SHaavard Skinnemoen 		dev_vdbg(&host->pdev->dev, "list empty\n");
1106965ebf33SHaavard Skinnemoen 		host->state = STATE_IDLE;
1107965ebf33SHaavard Skinnemoen 	}
1108965ebf33SHaavard Skinnemoen 
1109965ebf33SHaavard Skinnemoen 	spin_unlock(&host->lock);
1110965ebf33SHaavard Skinnemoen 	mmc_request_done(prev_mmc, mrq);
1111965ebf33SHaavard Skinnemoen 	spin_lock(&host->lock);
1112965ebf33SHaavard Skinnemoen }
1113965ebf33SHaavard Skinnemoen 
11147d2be074SHaavard Skinnemoen static void atmci_command_complete(struct atmel_mci *host,
1115c06ad258SHaavard Skinnemoen 			struct mmc_command *cmd)
11167d2be074SHaavard Skinnemoen {
1117c06ad258SHaavard Skinnemoen 	u32		status = host->cmd_status;
1118c06ad258SHaavard Skinnemoen 
11197d2be074SHaavard Skinnemoen 	/* Read the response from the card (up to 16 bytes) */
11207d2be074SHaavard Skinnemoen 	cmd->resp[0] = mci_readl(host, RSPR);
11217d2be074SHaavard Skinnemoen 	cmd->resp[1] = mci_readl(host, RSPR);
11227d2be074SHaavard Skinnemoen 	cmd->resp[2] = mci_readl(host, RSPR);
11237d2be074SHaavard Skinnemoen 	cmd->resp[3] = mci_readl(host, RSPR);
11247d2be074SHaavard Skinnemoen 
11257d2be074SHaavard Skinnemoen 	if (status & MCI_RTOE)
11267d2be074SHaavard Skinnemoen 		cmd->error = -ETIMEDOUT;
11277d2be074SHaavard Skinnemoen 	else if ((cmd->flags & MMC_RSP_CRC) && (status & MCI_RCRCE))
11287d2be074SHaavard Skinnemoen 		cmd->error = -EILSEQ;
11297d2be074SHaavard Skinnemoen 	else if (status & (MCI_RINDE | MCI_RDIRE | MCI_RENDE))
11307d2be074SHaavard Skinnemoen 		cmd->error = -EIO;
11317d2be074SHaavard Skinnemoen 	else
11327d2be074SHaavard Skinnemoen 		cmd->error = 0;
11337d2be074SHaavard Skinnemoen 
11347d2be074SHaavard Skinnemoen 	if (cmd->error) {
1135965ebf33SHaavard Skinnemoen 		dev_dbg(&host->pdev->dev,
11367d2be074SHaavard Skinnemoen 			"command error: status=0x%08x\n", status);
11377d2be074SHaavard Skinnemoen 
11387d2be074SHaavard Skinnemoen 		if (cmd->data) {
113965e8b083SHaavard Skinnemoen 			atmci_stop_dma(host);
1140009a891bSNicolas Ferre 			host->data = NULL;
11417d2be074SHaavard Skinnemoen 			mci_writel(host, IDR, MCI_NOTBUSY
11427d2be074SHaavard Skinnemoen 					| MCI_TXRDY | MCI_RXRDY
11437d2be074SHaavard Skinnemoen 					| ATMCI_DATA_ERROR_FLAGS);
11447d2be074SHaavard Skinnemoen 		}
11457d2be074SHaavard Skinnemoen 	}
11467d2be074SHaavard Skinnemoen }
11477d2be074SHaavard Skinnemoen 
11487d2be074SHaavard Skinnemoen static void atmci_detect_change(unsigned long data)
11497d2be074SHaavard Skinnemoen {
1150965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = (struct atmel_mci_slot *)data;
1151965ebf33SHaavard Skinnemoen 	bool			present;
1152965ebf33SHaavard Skinnemoen 	bool			present_old;
11537d2be074SHaavard Skinnemoen 
11547d2be074SHaavard Skinnemoen 	/*
1155965ebf33SHaavard Skinnemoen 	 * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
1156965ebf33SHaavard Skinnemoen 	 * freeing the interrupt. We must not re-enable the interrupt
1157965ebf33SHaavard Skinnemoen 	 * if it has been freed, and if we're shutting down, it
1158965ebf33SHaavard Skinnemoen 	 * doesn't really matter whether the card is present or not.
11597d2be074SHaavard Skinnemoen 	 */
11607d2be074SHaavard Skinnemoen 	smp_rmb();
1161965ebf33SHaavard Skinnemoen 	if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
11627d2be074SHaavard Skinnemoen 		return;
11637d2be074SHaavard Skinnemoen 
1164965ebf33SHaavard Skinnemoen 	enable_irq(gpio_to_irq(slot->detect_pin));
11651c1452beSJonas Larsson 	present = !(gpio_get_value(slot->detect_pin) ^
11661c1452beSJonas Larsson 		    slot->detect_is_active_high);
1167965ebf33SHaavard Skinnemoen 	present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
11687d2be074SHaavard Skinnemoen 
1169965ebf33SHaavard Skinnemoen 	dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
1170965ebf33SHaavard Skinnemoen 			present, present_old);
11717d2be074SHaavard Skinnemoen 
1172965ebf33SHaavard Skinnemoen 	if (present != present_old) {
1173965ebf33SHaavard Skinnemoen 		struct atmel_mci	*host = slot->host;
1174965ebf33SHaavard Skinnemoen 		struct mmc_request	*mrq;
1175965ebf33SHaavard Skinnemoen 
1176965ebf33SHaavard Skinnemoen 		dev_dbg(&slot->mmc->class_dev, "card %s\n",
11777d2be074SHaavard Skinnemoen 			present ? "inserted" : "removed");
11787d2be074SHaavard Skinnemoen 
1179965ebf33SHaavard Skinnemoen 		spin_lock(&host->lock);
1180965ebf33SHaavard Skinnemoen 
1181965ebf33SHaavard Skinnemoen 		if (!present)
1182965ebf33SHaavard Skinnemoen 			clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
1183965ebf33SHaavard Skinnemoen 		else
1184965ebf33SHaavard Skinnemoen 			set_bit(ATMCI_CARD_PRESENT, &slot->flags);
11857d2be074SHaavard Skinnemoen 
11867d2be074SHaavard Skinnemoen 		/* Clean up queue if present */
1187965ebf33SHaavard Skinnemoen 		mrq = slot->mrq;
11887d2be074SHaavard Skinnemoen 		if (mrq) {
1189965ebf33SHaavard Skinnemoen 			if (mrq == host->mrq) {
11907d2be074SHaavard Skinnemoen 				/*
11917d2be074SHaavard Skinnemoen 				 * Reset controller to terminate any ongoing
11927d2be074SHaavard Skinnemoen 				 * commands or data transfers.
11937d2be074SHaavard Skinnemoen 				 */
11947d2be074SHaavard Skinnemoen 				mci_writel(host, CR, MCI_CR_SWRST);
1195965ebf33SHaavard Skinnemoen 				mci_writel(host, CR, MCI_CR_MCIEN);
1196965ebf33SHaavard Skinnemoen 				mci_writel(host, MR, host->mode_reg);
119774791a2dSNicolas Ferre 				if (atmci_is_mci2())
119874791a2dSNicolas Ferre 					mci_writel(host, CFG, host->cfg_reg);
11997d2be074SHaavard Skinnemoen 
12007d2be074SHaavard Skinnemoen 				host->data = NULL;
12017d2be074SHaavard Skinnemoen 				host->cmd = NULL;
1202c06ad258SHaavard Skinnemoen 
1203c06ad258SHaavard Skinnemoen 				switch (host->state) {
1204965ebf33SHaavard Skinnemoen 				case STATE_IDLE:
1205965ebf33SHaavard Skinnemoen 					break;
1206c06ad258SHaavard Skinnemoen 				case STATE_SENDING_CMD:
1207c06ad258SHaavard Skinnemoen 					mrq->cmd->error = -ENOMEDIUM;
1208c06ad258SHaavard Skinnemoen 					if (!mrq->data)
1209c06ad258SHaavard Skinnemoen 						break;
1210c06ad258SHaavard Skinnemoen 					/* fall through */
1211c06ad258SHaavard Skinnemoen 				case STATE_SENDING_DATA:
1212c06ad258SHaavard Skinnemoen 					mrq->data->error = -ENOMEDIUM;
121365e8b083SHaavard Skinnemoen 					atmci_stop_dma(host);
1214c06ad258SHaavard Skinnemoen 					break;
1215c06ad258SHaavard Skinnemoen 				case STATE_DATA_BUSY:
1216c06ad258SHaavard Skinnemoen 				case STATE_DATA_ERROR:
1217c06ad258SHaavard Skinnemoen 					if (mrq->data->error == -EINPROGRESS)
1218c06ad258SHaavard Skinnemoen 						mrq->data->error = -ENOMEDIUM;
1219c06ad258SHaavard Skinnemoen 					if (!mrq->stop)
1220c06ad258SHaavard Skinnemoen 						break;
1221c06ad258SHaavard Skinnemoen 					/* fall through */
1222c06ad258SHaavard Skinnemoen 				case STATE_SENDING_STOP:
1223c06ad258SHaavard Skinnemoen 					mrq->stop->error = -ENOMEDIUM;
1224c06ad258SHaavard Skinnemoen 					break;
1225c06ad258SHaavard Skinnemoen 				}
1226c06ad258SHaavard Skinnemoen 
1227965ebf33SHaavard Skinnemoen 				atmci_request_end(host, mrq);
1228965ebf33SHaavard Skinnemoen 			} else {
1229965ebf33SHaavard Skinnemoen 				list_del(&slot->queue_node);
1230965ebf33SHaavard Skinnemoen 				mrq->cmd->error = -ENOMEDIUM;
1231965ebf33SHaavard Skinnemoen 				if (mrq->data)
1232965ebf33SHaavard Skinnemoen 					mrq->data->error = -ENOMEDIUM;
1233965ebf33SHaavard Skinnemoen 				if (mrq->stop)
1234965ebf33SHaavard Skinnemoen 					mrq->stop->error = -ENOMEDIUM;
12357d2be074SHaavard Skinnemoen 
1236965ebf33SHaavard Skinnemoen 				spin_unlock(&host->lock);
1237965ebf33SHaavard Skinnemoen 				mmc_request_done(slot->mmc, mrq);
1238965ebf33SHaavard Skinnemoen 				spin_lock(&host->lock);
1239965ebf33SHaavard Skinnemoen 			}
1240965ebf33SHaavard Skinnemoen 		}
1241965ebf33SHaavard Skinnemoen 		spin_unlock(&host->lock);
1242965ebf33SHaavard Skinnemoen 
1243965ebf33SHaavard Skinnemoen 		mmc_detect_change(slot->mmc, 0);
12447d2be074SHaavard Skinnemoen 	}
12457d2be074SHaavard Skinnemoen }
12467d2be074SHaavard Skinnemoen 
12477d2be074SHaavard Skinnemoen static void atmci_tasklet_func(unsigned long priv)
12487d2be074SHaavard Skinnemoen {
1249965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = (struct atmel_mci *)priv;
12507d2be074SHaavard Skinnemoen 	struct mmc_request	*mrq = host->mrq;
12517d2be074SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
1252c06ad258SHaavard Skinnemoen 	struct mmc_command	*cmd = host->cmd;
1253c06ad258SHaavard Skinnemoen 	enum atmel_mci_state	state = host->state;
1254c06ad258SHaavard Skinnemoen 	enum atmel_mci_state	prev_state;
1255c06ad258SHaavard Skinnemoen 	u32			status;
1256c06ad258SHaavard Skinnemoen 
1257965ebf33SHaavard Skinnemoen 	spin_lock(&host->lock);
1258965ebf33SHaavard Skinnemoen 
1259c06ad258SHaavard Skinnemoen 	state = host->state;
12607d2be074SHaavard Skinnemoen 
1261965ebf33SHaavard Skinnemoen 	dev_vdbg(&host->pdev->dev,
1262c06ad258SHaavard Skinnemoen 		"tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
1263c06ad258SHaavard Skinnemoen 		state, host->pending_events, host->completed_events,
12647d2be074SHaavard Skinnemoen 		mci_readl(host, IMR));
12657d2be074SHaavard Skinnemoen 
1266c06ad258SHaavard Skinnemoen 	do {
1267c06ad258SHaavard Skinnemoen 		prev_state = state;
1268c06ad258SHaavard Skinnemoen 
1269c06ad258SHaavard Skinnemoen 		switch (state) {
1270965ebf33SHaavard Skinnemoen 		case STATE_IDLE:
1271965ebf33SHaavard Skinnemoen 			break;
1272965ebf33SHaavard Skinnemoen 
1273c06ad258SHaavard Skinnemoen 		case STATE_SENDING_CMD:
1274c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1275c06ad258SHaavard Skinnemoen 						EVENT_CMD_COMPLETE))
1276c06ad258SHaavard Skinnemoen 				break;
1277c06ad258SHaavard Skinnemoen 
12787d2be074SHaavard Skinnemoen 			host->cmd = NULL;
12797d2be074SHaavard Skinnemoen 			atmci_set_completed(host, EVENT_CMD_COMPLETE);
1280c06ad258SHaavard Skinnemoen 			atmci_command_complete(host, mrq->cmd);
1281c06ad258SHaavard Skinnemoen 			if (!mrq->data || cmd->error) {
1282965ebf33SHaavard Skinnemoen 				atmci_request_end(host, host->mrq);
1283965ebf33SHaavard Skinnemoen 				goto unlock;
12847d2be074SHaavard Skinnemoen 			}
1285c06ad258SHaavard Skinnemoen 
1286c06ad258SHaavard Skinnemoen 			prev_state = state = STATE_SENDING_DATA;
1287c06ad258SHaavard Skinnemoen 			/* fall through */
1288c06ad258SHaavard Skinnemoen 
1289c06ad258SHaavard Skinnemoen 		case STATE_SENDING_DATA:
1290c06ad258SHaavard Skinnemoen 			if (atmci_test_and_clear_pending(host,
1291c06ad258SHaavard Skinnemoen 						EVENT_DATA_ERROR)) {
129265e8b083SHaavard Skinnemoen 				atmci_stop_dma(host);
1293c06ad258SHaavard Skinnemoen 				if (data->stop)
1294965ebf33SHaavard Skinnemoen 					send_stop_cmd(host, data);
1295c06ad258SHaavard Skinnemoen 				state = STATE_DATA_ERROR;
1296c06ad258SHaavard Skinnemoen 				break;
12977d2be074SHaavard Skinnemoen 			}
12987d2be074SHaavard Skinnemoen 
1299c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1300c06ad258SHaavard Skinnemoen 						EVENT_XFER_COMPLETE))
1301c06ad258SHaavard Skinnemoen 				break;
13027d2be074SHaavard Skinnemoen 
1303c06ad258SHaavard Skinnemoen 			atmci_set_completed(host, EVENT_XFER_COMPLETE);
1304c06ad258SHaavard Skinnemoen 			prev_state = state = STATE_DATA_BUSY;
1305c06ad258SHaavard Skinnemoen 			/* fall through */
1306c06ad258SHaavard Skinnemoen 
1307c06ad258SHaavard Skinnemoen 		case STATE_DATA_BUSY:
1308c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1309c06ad258SHaavard Skinnemoen 						EVENT_DATA_COMPLETE))
1310c06ad258SHaavard Skinnemoen 				break;
1311c06ad258SHaavard Skinnemoen 
1312c06ad258SHaavard Skinnemoen 			host->data = NULL;
13137d2be074SHaavard Skinnemoen 			atmci_set_completed(host, EVENT_DATA_COMPLETE);
1314c06ad258SHaavard Skinnemoen 			status = host->data_status;
1315c06ad258SHaavard Skinnemoen 			if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
13167d2be074SHaavard Skinnemoen 				if (status & MCI_DTOE) {
1317965ebf33SHaavard Skinnemoen 					dev_dbg(&host->pdev->dev,
13187d2be074SHaavard Skinnemoen 							"data timeout error\n");
13197d2be074SHaavard Skinnemoen 					data->error = -ETIMEDOUT;
13207d2be074SHaavard Skinnemoen 				} else if (status & MCI_DCRCE) {
1321965ebf33SHaavard Skinnemoen 					dev_dbg(&host->pdev->dev,
1322c06ad258SHaavard Skinnemoen 							"data CRC error\n");
13237d2be074SHaavard Skinnemoen 					data->error = -EILSEQ;
13247d2be074SHaavard Skinnemoen 				} else {
1325965ebf33SHaavard Skinnemoen 					dev_dbg(&host->pdev->dev,
13267d2be074SHaavard Skinnemoen 						"data FIFO error (status=%08x)\n",
13277d2be074SHaavard Skinnemoen 						status);
13287d2be074SHaavard Skinnemoen 					data->error = -EIO;
13297d2be074SHaavard Skinnemoen 				}
1330c06ad258SHaavard Skinnemoen 			} else {
13317d2be074SHaavard Skinnemoen 				data->bytes_xfered = data->blocks * data->blksz;
13327d2be074SHaavard Skinnemoen 				data->error = 0;
1333abc2c9fdSNicolas Ferre 				mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS);
13347d2be074SHaavard Skinnemoen 			}
13357d2be074SHaavard Skinnemoen 
1336c06ad258SHaavard Skinnemoen 			if (!data->stop) {
1337965ebf33SHaavard Skinnemoen 				atmci_request_end(host, host->mrq);
1338965ebf33SHaavard Skinnemoen 				goto unlock;
13397d2be074SHaavard Skinnemoen 			}
13407d2be074SHaavard Skinnemoen 
1341c06ad258SHaavard Skinnemoen 			prev_state = state = STATE_SENDING_STOP;
1342c06ad258SHaavard Skinnemoen 			if (!data->error)
1343965ebf33SHaavard Skinnemoen 				send_stop_cmd(host, data);
1344c06ad258SHaavard Skinnemoen 			/* fall through */
1345c06ad258SHaavard Skinnemoen 
1346c06ad258SHaavard Skinnemoen 		case STATE_SENDING_STOP:
1347c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1348c06ad258SHaavard Skinnemoen 						EVENT_CMD_COMPLETE))
1349c06ad258SHaavard Skinnemoen 				break;
1350c06ad258SHaavard Skinnemoen 
1351c06ad258SHaavard Skinnemoen 			host->cmd = NULL;
1352c06ad258SHaavard Skinnemoen 			atmci_command_complete(host, mrq->stop);
1353965ebf33SHaavard Skinnemoen 			atmci_request_end(host, host->mrq);
1354965ebf33SHaavard Skinnemoen 			goto unlock;
1355c06ad258SHaavard Skinnemoen 
1356c06ad258SHaavard Skinnemoen 		case STATE_DATA_ERROR:
1357c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1358c06ad258SHaavard Skinnemoen 						EVENT_XFER_COMPLETE))
1359c06ad258SHaavard Skinnemoen 				break;
1360c06ad258SHaavard Skinnemoen 
1361c06ad258SHaavard Skinnemoen 			state = STATE_DATA_BUSY;
1362c06ad258SHaavard Skinnemoen 			break;
1363c06ad258SHaavard Skinnemoen 		}
1364c06ad258SHaavard Skinnemoen 	} while (state != prev_state);
1365c06ad258SHaavard Skinnemoen 
1366c06ad258SHaavard Skinnemoen 	host->state = state;
1367965ebf33SHaavard Skinnemoen 
1368965ebf33SHaavard Skinnemoen unlock:
1369965ebf33SHaavard Skinnemoen 	spin_unlock(&host->lock);
13707d2be074SHaavard Skinnemoen }
13717d2be074SHaavard Skinnemoen 
13727d2be074SHaavard Skinnemoen static void atmci_read_data_pio(struct atmel_mci *host)
13737d2be074SHaavard Skinnemoen {
13747d2be074SHaavard Skinnemoen 	struct scatterlist	*sg = host->sg;
13757d2be074SHaavard Skinnemoen 	void			*buf = sg_virt(sg);
13767d2be074SHaavard Skinnemoen 	unsigned int		offset = host->pio_offset;
13777d2be074SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
13787d2be074SHaavard Skinnemoen 	u32			value;
13797d2be074SHaavard Skinnemoen 	u32			status;
13807d2be074SHaavard Skinnemoen 	unsigned int		nbytes = 0;
13817d2be074SHaavard Skinnemoen 
13827d2be074SHaavard Skinnemoen 	do {
13837d2be074SHaavard Skinnemoen 		value = mci_readl(host, RDR);
13847d2be074SHaavard Skinnemoen 		if (likely(offset + 4 <= sg->length)) {
13857d2be074SHaavard Skinnemoen 			put_unaligned(value, (u32 *)(buf + offset));
13867d2be074SHaavard Skinnemoen 
13877d2be074SHaavard Skinnemoen 			offset += 4;
13887d2be074SHaavard Skinnemoen 			nbytes += 4;
13897d2be074SHaavard Skinnemoen 
13907d2be074SHaavard Skinnemoen 			if (offset == sg->length) {
13915e7184aeSHaavard Skinnemoen 				flush_dcache_page(sg_page(sg));
13927d2be074SHaavard Skinnemoen 				host->sg = sg = sg_next(sg);
13937d2be074SHaavard Skinnemoen 				if (!sg)
13947d2be074SHaavard Skinnemoen 					goto done;
13957d2be074SHaavard Skinnemoen 
13967d2be074SHaavard Skinnemoen 				offset = 0;
13977d2be074SHaavard Skinnemoen 				buf = sg_virt(sg);
13987d2be074SHaavard Skinnemoen 			}
13997d2be074SHaavard Skinnemoen 		} else {
14007d2be074SHaavard Skinnemoen 			unsigned int remaining = sg->length - offset;
14017d2be074SHaavard Skinnemoen 			memcpy(buf + offset, &value, remaining);
14027d2be074SHaavard Skinnemoen 			nbytes += remaining;
14037d2be074SHaavard Skinnemoen 
14047d2be074SHaavard Skinnemoen 			flush_dcache_page(sg_page(sg));
14057d2be074SHaavard Skinnemoen 			host->sg = sg = sg_next(sg);
14067d2be074SHaavard Skinnemoen 			if (!sg)
14077d2be074SHaavard Skinnemoen 				goto done;
14087d2be074SHaavard Skinnemoen 
14097d2be074SHaavard Skinnemoen 			offset = 4 - remaining;
14107d2be074SHaavard Skinnemoen 			buf = sg_virt(sg);
14117d2be074SHaavard Skinnemoen 			memcpy(buf, (u8 *)&value + remaining, offset);
14127d2be074SHaavard Skinnemoen 			nbytes += offset;
14137d2be074SHaavard Skinnemoen 		}
14147d2be074SHaavard Skinnemoen 
14157d2be074SHaavard Skinnemoen 		status = mci_readl(host, SR);
14167d2be074SHaavard Skinnemoen 		if (status & ATMCI_DATA_ERROR_FLAGS) {
14177d2be074SHaavard Skinnemoen 			mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY
14187d2be074SHaavard Skinnemoen 						| ATMCI_DATA_ERROR_FLAGS));
14197d2be074SHaavard Skinnemoen 			host->data_status = status;
1420965ebf33SHaavard Skinnemoen 			data->bytes_xfered += nbytes;
1421965ebf33SHaavard Skinnemoen 			smp_wmb();
14227d2be074SHaavard Skinnemoen 			atmci_set_pending(host, EVENT_DATA_ERROR);
14237d2be074SHaavard Skinnemoen 			tasklet_schedule(&host->tasklet);
1424965ebf33SHaavard Skinnemoen 			return;
14257d2be074SHaavard Skinnemoen 		}
14267d2be074SHaavard Skinnemoen 	} while (status & MCI_RXRDY);
14277d2be074SHaavard Skinnemoen 
14287d2be074SHaavard Skinnemoen 	host->pio_offset = offset;
14297d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
14307d2be074SHaavard Skinnemoen 
14317d2be074SHaavard Skinnemoen 	return;
14327d2be074SHaavard Skinnemoen 
14337d2be074SHaavard Skinnemoen done:
14347d2be074SHaavard Skinnemoen 	mci_writel(host, IDR, MCI_RXRDY);
14357d2be074SHaavard Skinnemoen 	mci_writel(host, IER, MCI_NOTBUSY);
14367d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
1437965ebf33SHaavard Skinnemoen 	smp_wmb();
1438c06ad258SHaavard Skinnemoen 	atmci_set_pending(host, EVENT_XFER_COMPLETE);
14397d2be074SHaavard Skinnemoen }
14407d2be074SHaavard Skinnemoen 
14417d2be074SHaavard Skinnemoen static void atmci_write_data_pio(struct atmel_mci *host)
14427d2be074SHaavard Skinnemoen {
14437d2be074SHaavard Skinnemoen 	struct scatterlist	*sg = host->sg;
14447d2be074SHaavard Skinnemoen 	void			*buf = sg_virt(sg);
14457d2be074SHaavard Skinnemoen 	unsigned int		offset = host->pio_offset;
14467d2be074SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
14477d2be074SHaavard Skinnemoen 	u32			value;
14487d2be074SHaavard Skinnemoen 	u32			status;
14497d2be074SHaavard Skinnemoen 	unsigned int		nbytes = 0;
14507d2be074SHaavard Skinnemoen 
14517d2be074SHaavard Skinnemoen 	do {
14527d2be074SHaavard Skinnemoen 		if (likely(offset + 4 <= sg->length)) {
14537d2be074SHaavard Skinnemoen 			value = get_unaligned((u32 *)(buf + offset));
14547d2be074SHaavard Skinnemoen 			mci_writel(host, TDR, value);
14557d2be074SHaavard Skinnemoen 
14567d2be074SHaavard Skinnemoen 			offset += 4;
14577d2be074SHaavard Skinnemoen 			nbytes += 4;
14587d2be074SHaavard Skinnemoen 			if (offset == sg->length) {
14597d2be074SHaavard Skinnemoen 				host->sg = sg = sg_next(sg);
14607d2be074SHaavard Skinnemoen 				if (!sg)
14617d2be074SHaavard Skinnemoen 					goto done;
14627d2be074SHaavard Skinnemoen 
14637d2be074SHaavard Skinnemoen 				offset = 0;
14647d2be074SHaavard Skinnemoen 				buf = sg_virt(sg);
14657d2be074SHaavard Skinnemoen 			}
14667d2be074SHaavard Skinnemoen 		} else {
14677d2be074SHaavard Skinnemoen 			unsigned int remaining = sg->length - offset;
14687d2be074SHaavard Skinnemoen 
14697d2be074SHaavard Skinnemoen 			value = 0;
14707d2be074SHaavard Skinnemoen 			memcpy(&value, buf + offset, remaining);
14717d2be074SHaavard Skinnemoen 			nbytes += remaining;
14727d2be074SHaavard Skinnemoen 
14737d2be074SHaavard Skinnemoen 			host->sg = sg = sg_next(sg);
14747d2be074SHaavard Skinnemoen 			if (!sg) {
14757d2be074SHaavard Skinnemoen 				mci_writel(host, TDR, value);
14767d2be074SHaavard Skinnemoen 				goto done;
14777d2be074SHaavard Skinnemoen 			}
14787d2be074SHaavard Skinnemoen 
14797d2be074SHaavard Skinnemoen 			offset = 4 - remaining;
14807d2be074SHaavard Skinnemoen 			buf = sg_virt(sg);
14817d2be074SHaavard Skinnemoen 			memcpy((u8 *)&value + remaining, buf, offset);
14827d2be074SHaavard Skinnemoen 			mci_writel(host, TDR, value);
14837d2be074SHaavard Skinnemoen 			nbytes += offset;
14847d2be074SHaavard Skinnemoen 		}
14857d2be074SHaavard Skinnemoen 
14867d2be074SHaavard Skinnemoen 		status = mci_readl(host, SR);
14877d2be074SHaavard Skinnemoen 		if (status & ATMCI_DATA_ERROR_FLAGS) {
14887d2be074SHaavard Skinnemoen 			mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY
14897d2be074SHaavard Skinnemoen 						| ATMCI_DATA_ERROR_FLAGS));
14907d2be074SHaavard Skinnemoen 			host->data_status = status;
1491965ebf33SHaavard Skinnemoen 			data->bytes_xfered += nbytes;
1492965ebf33SHaavard Skinnemoen 			smp_wmb();
14937d2be074SHaavard Skinnemoen 			atmci_set_pending(host, EVENT_DATA_ERROR);
14947d2be074SHaavard Skinnemoen 			tasklet_schedule(&host->tasklet);
1495965ebf33SHaavard Skinnemoen 			return;
14967d2be074SHaavard Skinnemoen 		}
14977d2be074SHaavard Skinnemoen 	} while (status & MCI_TXRDY);
14987d2be074SHaavard Skinnemoen 
14997d2be074SHaavard Skinnemoen 	host->pio_offset = offset;
15007d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
15017d2be074SHaavard Skinnemoen 
15027d2be074SHaavard Skinnemoen 	return;
15037d2be074SHaavard Skinnemoen 
15047d2be074SHaavard Skinnemoen done:
15057d2be074SHaavard Skinnemoen 	mci_writel(host, IDR, MCI_TXRDY);
15067d2be074SHaavard Skinnemoen 	mci_writel(host, IER, MCI_NOTBUSY);
15077d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
1508965ebf33SHaavard Skinnemoen 	smp_wmb();
1509c06ad258SHaavard Skinnemoen 	atmci_set_pending(host, EVENT_XFER_COMPLETE);
15107d2be074SHaavard Skinnemoen }
15117d2be074SHaavard Skinnemoen 
1512965ebf33SHaavard Skinnemoen static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
15137d2be074SHaavard Skinnemoen {
15147d2be074SHaavard Skinnemoen 	mci_writel(host, IDR, MCI_CMDRDY);
15157d2be074SHaavard Skinnemoen 
15167d2be074SHaavard Skinnemoen 	host->cmd_status = status;
1517965ebf33SHaavard Skinnemoen 	smp_wmb();
15187d2be074SHaavard Skinnemoen 	atmci_set_pending(host, EVENT_CMD_COMPLETE);
15197d2be074SHaavard Skinnemoen 	tasklet_schedule(&host->tasklet);
15207d2be074SHaavard Skinnemoen }
15217d2be074SHaavard Skinnemoen 
152288ff82edSAnders Grahn static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
152388ff82edSAnders Grahn {
152488ff82edSAnders Grahn 	int	i;
152588ff82edSAnders Grahn 
152688ff82edSAnders Grahn 	for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
152788ff82edSAnders Grahn 		struct atmel_mci_slot *slot = host->slot[i];
152888ff82edSAnders Grahn 		if (slot && (status & slot->sdio_irq)) {
152988ff82edSAnders Grahn 			mmc_signal_sdio_irq(slot->mmc);
153088ff82edSAnders Grahn 		}
153188ff82edSAnders Grahn 	}
153288ff82edSAnders Grahn }
153388ff82edSAnders Grahn 
153488ff82edSAnders Grahn 
15357d2be074SHaavard Skinnemoen static irqreturn_t atmci_interrupt(int irq, void *dev_id)
15367d2be074SHaavard Skinnemoen {
1537965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = dev_id;
15387d2be074SHaavard Skinnemoen 	u32			status, mask, pending;
15397d2be074SHaavard Skinnemoen 	unsigned int		pass_count = 0;
15407d2be074SHaavard Skinnemoen 
15417d2be074SHaavard Skinnemoen 	do {
15427d2be074SHaavard Skinnemoen 		status = mci_readl(host, SR);
15437d2be074SHaavard Skinnemoen 		mask = mci_readl(host, IMR);
15447d2be074SHaavard Skinnemoen 		pending = status & mask;
15457d2be074SHaavard Skinnemoen 		if (!pending)
15467d2be074SHaavard Skinnemoen 			break;
15477d2be074SHaavard Skinnemoen 
15487d2be074SHaavard Skinnemoen 		if (pending & ATMCI_DATA_ERROR_FLAGS) {
15497d2be074SHaavard Skinnemoen 			mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS
15507d2be074SHaavard Skinnemoen 					| MCI_RXRDY | MCI_TXRDY);
15517d2be074SHaavard Skinnemoen 			pending &= mci_readl(host, IMR);
1552965ebf33SHaavard Skinnemoen 
15537d2be074SHaavard Skinnemoen 			host->data_status = status;
1554965ebf33SHaavard Skinnemoen 			smp_wmb();
15557d2be074SHaavard Skinnemoen 			atmci_set_pending(host, EVENT_DATA_ERROR);
15567d2be074SHaavard Skinnemoen 			tasklet_schedule(&host->tasklet);
15577d2be074SHaavard Skinnemoen 		}
15587d2be074SHaavard Skinnemoen 		if (pending & MCI_NOTBUSY) {
1559c06ad258SHaavard Skinnemoen 			mci_writel(host, IDR,
1560c06ad258SHaavard Skinnemoen 					ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY);
1561ca55f46eSHaavard Skinnemoen 			if (!host->data_status)
1562c06ad258SHaavard Skinnemoen 				host->data_status = status;
1563965ebf33SHaavard Skinnemoen 			smp_wmb();
15647d2be074SHaavard Skinnemoen 			atmci_set_pending(host, EVENT_DATA_COMPLETE);
15657d2be074SHaavard Skinnemoen 			tasklet_schedule(&host->tasklet);
15667d2be074SHaavard Skinnemoen 		}
15677d2be074SHaavard Skinnemoen 		if (pending & MCI_RXRDY)
15687d2be074SHaavard Skinnemoen 			atmci_read_data_pio(host);
15697d2be074SHaavard Skinnemoen 		if (pending & MCI_TXRDY)
15707d2be074SHaavard Skinnemoen 			atmci_write_data_pio(host);
15717d2be074SHaavard Skinnemoen 
15727d2be074SHaavard Skinnemoen 		if (pending & MCI_CMDRDY)
1573965ebf33SHaavard Skinnemoen 			atmci_cmd_interrupt(host, status);
157488ff82edSAnders Grahn 
157588ff82edSAnders Grahn 		if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB))
157688ff82edSAnders Grahn 			atmci_sdio_interrupt(host, status);
157788ff82edSAnders Grahn 
15787d2be074SHaavard Skinnemoen 	} while (pass_count++ < 5);
15797d2be074SHaavard Skinnemoen 
15807d2be074SHaavard Skinnemoen 	return pass_count ? IRQ_HANDLED : IRQ_NONE;
15817d2be074SHaavard Skinnemoen }
15827d2be074SHaavard Skinnemoen 
15837d2be074SHaavard Skinnemoen static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
15847d2be074SHaavard Skinnemoen {
1585965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = dev_id;
15867d2be074SHaavard Skinnemoen 
15877d2be074SHaavard Skinnemoen 	/*
15887d2be074SHaavard Skinnemoen 	 * Disable interrupts until the pin has stabilized and check
15897d2be074SHaavard Skinnemoen 	 * the state then. Use mod_timer() since we may be in the
15907d2be074SHaavard Skinnemoen 	 * middle of the timer routine when this interrupt triggers.
15917d2be074SHaavard Skinnemoen 	 */
15927d2be074SHaavard Skinnemoen 	disable_irq_nosync(irq);
1593965ebf33SHaavard Skinnemoen 	mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
15947d2be074SHaavard Skinnemoen 
15957d2be074SHaavard Skinnemoen 	return IRQ_HANDLED;
15967d2be074SHaavard Skinnemoen }
15977d2be074SHaavard Skinnemoen 
1598965ebf33SHaavard Skinnemoen static int __init atmci_init_slot(struct atmel_mci *host,
1599965ebf33SHaavard Skinnemoen 		struct mci_slot_pdata *slot_data, unsigned int id,
160088ff82edSAnders Grahn 		u32 sdc_reg, u32 sdio_irq)
1601965ebf33SHaavard Skinnemoen {
1602965ebf33SHaavard Skinnemoen 	struct mmc_host			*mmc;
1603965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot		*slot;
1604965ebf33SHaavard Skinnemoen 
1605965ebf33SHaavard Skinnemoen 	mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
1606965ebf33SHaavard Skinnemoen 	if (!mmc)
1607965ebf33SHaavard Skinnemoen 		return -ENOMEM;
1608965ebf33SHaavard Skinnemoen 
1609965ebf33SHaavard Skinnemoen 	slot = mmc_priv(mmc);
1610965ebf33SHaavard Skinnemoen 	slot->mmc = mmc;
1611965ebf33SHaavard Skinnemoen 	slot->host = host;
1612965ebf33SHaavard Skinnemoen 	slot->detect_pin = slot_data->detect_pin;
1613965ebf33SHaavard Skinnemoen 	slot->wp_pin = slot_data->wp_pin;
16141c1452beSJonas Larsson 	slot->detect_is_active_high = slot_data->detect_is_active_high;
1615965ebf33SHaavard Skinnemoen 	slot->sdc_reg = sdc_reg;
161688ff82edSAnders Grahn 	slot->sdio_irq = sdio_irq;
1617965ebf33SHaavard Skinnemoen 
1618965ebf33SHaavard Skinnemoen 	mmc->ops = &atmci_ops;
1619965ebf33SHaavard Skinnemoen 	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
1620965ebf33SHaavard Skinnemoen 	mmc->f_max = host->bus_hz / 2;
1621965ebf33SHaavard Skinnemoen 	mmc->ocr_avail	= MMC_VDD_32_33 | MMC_VDD_33_34;
162288ff82edSAnders Grahn 	if (sdio_irq)
162388ff82edSAnders Grahn 		mmc->caps |= MMC_CAP_SDIO_IRQ;
162499ddffd8SNicolas Ferre 	if (atmci_is_mci2())
162599ddffd8SNicolas Ferre 		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
1626965ebf33SHaavard Skinnemoen 	if (slot_data->bus_width >= 4)
1627965ebf33SHaavard Skinnemoen 		mmc->caps |= MMC_CAP_4_BIT_DATA;
1628965ebf33SHaavard Skinnemoen 
1629a36274e0SMartin K. Petersen 	mmc->max_segs = 64;
1630965ebf33SHaavard Skinnemoen 	mmc->max_req_size = 32768 * 512;
1631965ebf33SHaavard Skinnemoen 	mmc->max_blk_size = 32768;
1632965ebf33SHaavard Skinnemoen 	mmc->max_blk_count = 512;
1633965ebf33SHaavard Skinnemoen 
1634965ebf33SHaavard Skinnemoen 	/* Assume card is present initially */
1635965ebf33SHaavard Skinnemoen 	set_bit(ATMCI_CARD_PRESENT, &slot->flags);
1636965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
1637965ebf33SHaavard Skinnemoen 		if (gpio_request(slot->detect_pin, "mmc_detect")) {
1638965ebf33SHaavard Skinnemoen 			dev_dbg(&mmc->class_dev, "no detect pin available\n");
1639965ebf33SHaavard Skinnemoen 			slot->detect_pin = -EBUSY;
16401c1452beSJonas Larsson 		} else if (gpio_get_value(slot->detect_pin) ^
16411c1452beSJonas Larsson 				slot->detect_is_active_high) {
1642965ebf33SHaavard Skinnemoen 			clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
1643965ebf33SHaavard Skinnemoen 		}
1644965ebf33SHaavard Skinnemoen 	}
1645965ebf33SHaavard Skinnemoen 
1646965ebf33SHaavard Skinnemoen 	if (!gpio_is_valid(slot->detect_pin))
1647965ebf33SHaavard Skinnemoen 		mmc->caps |= MMC_CAP_NEEDS_POLL;
1648965ebf33SHaavard Skinnemoen 
1649965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->wp_pin)) {
1650965ebf33SHaavard Skinnemoen 		if (gpio_request(slot->wp_pin, "mmc_wp")) {
1651965ebf33SHaavard Skinnemoen 			dev_dbg(&mmc->class_dev, "no WP pin available\n");
1652965ebf33SHaavard Skinnemoen 			slot->wp_pin = -EBUSY;
1653965ebf33SHaavard Skinnemoen 		}
1654965ebf33SHaavard Skinnemoen 	}
1655965ebf33SHaavard Skinnemoen 
1656965ebf33SHaavard Skinnemoen 	host->slot[id] = slot;
1657965ebf33SHaavard Skinnemoen 	mmc_add_host(mmc);
1658965ebf33SHaavard Skinnemoen 
1659965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
1660965ebf33SHaavard Skinnemoen 		int ret;
1661965ebf33SHaavard Skinnemoen 
1662965ebf33SHaavard Skinnemoen 		setup_timer(&slot->detect_timer, atmci_detect_change,
1663965ebf33SHaavard Skinnemoen 				(unsigned long)slot);
1664965ebf33SHaavard Skinnemoen 
1665965ebf33SHaavard Skinnemoen 		ret = request_irq(gpio_to_irq(slot->detect_pin),
1666965ebf33SHaavard Skinnemoen 				atmci_detect_interrupt,
1667965ebf33SHaavard Skinnemoen 				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
1668965ebf33SHaavard Skinnemoen 				"mmc-detect", slot);
1669965ebf33SHaavard Skinnemoen 		if (ret) {
1670965ebf33SHaavard Skinnemoen 			dev_dbg(&mmc->class_dev,
1671965ebf33SHaavard Skinnemoen 				"could not request IRQ %d for detect pin\n",
1672965ebf33SHaavard Skinnemoen 				gpio_to_irq(slot->detect_pin));
1673965ebf33SHaavard Skinnemoen 			gpio_free(slot->detect_pin);
1674965ebf33SHaavard Skinnemoen 			slot->detect_pin = -EBUSY;
1675965ebf33SHaavard Skinnemoen 		}
1676965ebf33SHaavard Skinnemoen 	}
1677965ebf33SHaavard Skinnemoen 
1678965ebf33SHaavard Skinnemoen 	atmci_init_debugfs(slot);
1679965ebf33SHaavard Skinnemoen 
1680965ebf33SHaavard Skinnemoen 	return 0;
1681965ebf33SHaavard Skinnemoen }
1682965ebf33SHaavard Skinnemoen 
1683965ebf33SHaavard Skinnemoen static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
1684965ebf33SHaavard Skinnemoen 		unsigned int id)
1685965ebf33SHaavard Skinnemoen {
1686965ebf33SHaavard Skinnemoen 	/* Debugfs stuff is cleaned up by mmc core */
1687965ebf33SHaavard Skinnemoen 
1688965ebf33SHaavard Skinnemoen 	set_bit(ATMCI_SHUTDOWN, &slot->flags);
1689965ebf33SHaavard Skinnemoen 	smp_wmb();
1690965ebf33SHaavard Skinnemoen 
1691965ebf33SHaavard Skinnemoen 	mmc_remove_host(slot->mmc);
1692965ebf33SHaavard Skinnemoen 
1693965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
1694965ebf33SHaavard Skinnemoen 		int pin = slot->detect_pin;
1695965ebf33SHaavard Skinnemoen 
1696965ebf33SHaavard Skinnemoen 		free_irq(gpio_to_irq(pin), slot);
1697965ebf33SHaavard Skinnemoen 		del_timer_sync(&slot->detect_timer);
1698965ebf33SHaavard Skinnemoen 		gpio_free(pin);
1699965ebf33SHaavard Skinnemoen 	}
1700965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->wp_pin))
1701965ebf33SHaavard Skinnemoen 		gpio_free(slot->wp_pin);
1702965ebf33SHaavard Skinnemoen 
1703965ebf33SHaavard Skinnemoen 	slot->host->slot[id] = NULL;
1704965ebf33SHaavard Skinnemoen 	mmc_free_host(slot->mmc);
1705965ebf33SHaavard Skinnemoen }
1706965ebf33SHaavard Skinnemoen 
170774465b4fSDan Williams #ifdef CONFIG_MMC_ATMELMCI_DMA
17087dd60251SDan Williams static bool filter(struct dma_chan *chan, void *slave)
170974465b4fSDan Williams {
17102635d1baSNicolas Ferre 	struct mci_dma_data	*sl = slave;
171174465b4fSDan Williams 
17122635d1baSNicolas Ferre 	if (sl && find_slave_dev(sl) == chan->device->dev) {
17132635d1baSNicolas Ferre 		chan->private = slave_data_ptr(sl);
17147dd60251SDan Williams 		return true;
17152635d1baSNicolas Ferre 	} else {
17167dd60251SDan Williams 		return false;
171774465b4fSDan Williams 	}
17182635d1baSNicolas Ferre }
17192635d1baSNicolas Ferre 
17202635d1baSNicolas Ferre static void atmci_configure_dma(struct atmel_mci *host)
17212635d1baSNicolas Ferre {
17222635d1baSNicolas Ferre 	struct mci_platform_data	*pdata;
17232635d1baSNicolas Ferre 
17242635d1baSNicolas Ferre 	if (host == NULL)
17252635d1baSNicolas Ferre 		return;
17262635d1baSNicolas Ferre 
17272635d1baSNicolas Ferre 	pdata = host->pdev->dev.platform_data;
17282635d1baSNicolas Ferre 
17292635d1baSNicolas Ferre 	if (pdata && find_slave_dev(pdata->dma_slave)) {
17302635d1baSNicolas Ferre 		dma_cap_mask_t mask;
17312635d1baSNicolas Ferre 
17322635d1baSNicolas Ferre 		setup_dma_addr(pdata->dma_slave,
17332635d1baSNicolas Ferre 			       host->mapbase + MCI_TDR,
17342635d1baSNicolas Ferre 			       host->mapbase + MCI_RDR);
17352635d1baSNicolas Ferre 
17362635d1baSNicolas Ferre 		/* Try to grab a DMA channel */
17372635d1baSNicolas Ferre 		dma_cap_zero(mask);
17382635d1baSNicolas Ferre 		dma_cap_set(DMA_SLAVE, mask);
17392635d1baSNicolas Ferre 		host->dma.chan =
17402635d1baSNicolas Ferre 			dma_request_channel(mask, filter, pdata->dma_slave);
17412635d1baSNicolas Ferre 	}
17422635d1baSNicolas Ferre 	if (!host->dma.chan)
17432635d1baSNicolas Ferre 		dev_notice(&host->pdev->dev, "DMA not available, using PIO\n");
174474791a2dSNicolas Ferre 	else
174574791a2dSNicolas Ferre 		dev_info(&host->pdev->dev,
174674791a2dSNicolas Ferre 					"Using %s for DMA transfers\n",
174774791a2dSNicolas Ferre 					dma_chan_name(host->dma.chan));
17482635d1baSNicolas Ferre }
17492635d1baSNicolas Ferre #else
17502635d1baSNicolas Ferre static void atmci_configure_dma(struct atmel_mci *host) {}
175174465b4fSDan Williams #endif
175274465b4fSDan Williams 
17537d2be074SHaavard Skinnemoen static int __init atmci_probe(struct platform_device *pdev)
17547d2be074SHaavard Skinnemoen {
17557d2be074SHaavard Skinnemoen 	struct mci_platform_data	*pdata;
17567d2be074SHaavard Skinnemoen 	struct atmel_mci		*host;
17577d2be074SHaavard Skinnemoen 	struct resource			*regs;
1758965ebf33SHaavard Skinnemoen 	unsigned int			nr_slots;
17597d2be074SHaavard Skinnemoen 	int				irq;
17607d2be074SHaavard Skinnemoen 	int				ret;
17617d2be074SHaavard Skinnemoen 
17627d2be074SHaavard Skinnemoen 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
17637d2be074SHaavard Skinnemoen 	if (!regs)
17647d2be074SHaavard Skinnemoen 		return -ENXIO;
17657d2be074SHaavard Skinnemoen 	pdata = pdev->dev.platform_data;
17667d2be074SHaavard Skinnemoen 	if (!pdata)
17677d2be074SHaavard Skinnemoen 		return -ENXIO;
17687d2be074SHaavard Skinnemoen 	irq = platform_get_irq(pdev, 0);
17697d2be074SHaavard Skinnemoen 	if (irq < 0)
17707d2be074SHaavard Skinnemoen 		return irq;
17717d2be074SHaavard Skinnemoen 
1772965ebf33SHaavard Skinnemoen 	host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
1773965ebf33SHaavard Skinnemoen 	if (!host)
17747d2be074SHaavard Skinnemoen 		return -ENOMEM;
17757d2be074SHaavard Skinnemoen 
17767d2be074SHaavard Skinnemoen 	host->pdev = pdev;
1777965ebf33SHaavard Skinnemoen 	spin_lock_init(&host->lock);
1778965ebf33SHaavard Skinnemoen 	INIT_LIST_HEAD(&host->queue);
17797d2be074SHaavard Skinnemoen 
17807d2be074SHaavard Skinnemoen 	host->mck = clk_get(&pdev->dev, "mci_clk");
17817d2be074SHaavard Skinnemoen 	if (IS_ERR(host->mck)) {
17827d2be074SHaavard Skinnemoen 		ret = PTR_ERR(host->mck);
17837d2be074SHaavard Skinnemoen 		goto err_clk_get;
17847d2be074SHaavard Skinnemoen 	}
17857d2be074SHaavard Skinnemoen 
17867d2be074SHaavard Skinnemoen 	ret = -ENOMEM;
1787e8e3f6caSH Hartley Sweeten 	host->regs = ioremap(regs->start, resource_size(regs));
17887d2be074SHaavard Skinnemoen 	if (!host->regs)
17897d2be074SHaavard Skinnemoen 		goto err_ioremap;
17907d2be074SHaavard Skinnemoen 
17917d2be074SHaavard Skinnemoen 	clk_enable(host->mck);
17927d2be074SHaavard Skinnemoen 	mci_writel(host, CR, MCI_CR_SWRST);
17937d2be074SHaavard Skinnemoen 	host->bus_hz = clk_get_rate(host->mck);
17947d2be074SHaavard Skinnemoen 	clk_disable(host->mck);
17957d2be074SHaavard Skinnemoen 
17967d2be074SHaavard Skinnemoen 	host->mapbase = regs->start;
17977d2be074SHaavard Skinnemoen 
1798965ebf33SHaavard Skinnemoen 	tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
17997d2be074SHaavard Skinnemoen 
180089c8aa20SKay Sievers 	ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
18017d2be074SHaavard Skinnemoen 	if (ret)
18027d2be074SHaavard Skinnemoen 		goto err_request_irq;
18037d2be074SHaavard Skinnemoen 
18042635d1baSNicolas Ferre 	atmci_configure_dma(host);
180565e8b083SHaavard Skinnemoen 
18067d2be074SHaavard Skinnemoen 	platform_set_drvdata(pdev, host);
18077d2be074SHaavard Skinnemoen 
1808965ebf33SHaavard Skinnemoen 	/* We need at least one slot to succeed */
1809965ebf33SHaavard Skinnemoen 	nr_slots = 0;
1810965ebf33SHaavard Skinnemoen 	ret = -ENODEV;
1811965ebf33SHaavard Skinnemoen 	if (pdata->slot[0].bus_width) {
1812965ebf33SHaavard Skinnemoen 		ret = atmci_init_slot(host, &pdata->slot[0],
181388ff82edSAnders Grahn 				0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA);
1814965ebf33SHaavard Skinnemoen 		if (!ret)
1815965ebf33SHaavard Skinnemoen 			nr_slots++;
18167d2be074SHaavard Skinnemoen 	}
1817965ebf33SHaavard Skinnemoen 	if (pdata->slot[1].bus_width) {
1818965ebf33SHaavard Skinnemoen 		ret = atmci_init_slot(host, &pdata->slot[1],
181988ff82edSAnders Grahn 				1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB);
1820965ebf33SHaavard Skinnemoen 		if (!ret)
1821965ebf33SHaavard Skinnemoen 			nr_slots++;
18227d2be074SHaavard Skinnemoen 	}
18237d2be074SHaavard Skinnemoen 
182404d699c3SRob Emanuele 	if (!nr_slots) {
182504d699c3SRob Emanuele 		dev_err(&pdev->dev, "init failed: no slot defined\n");
1826965ebf33SHaavard Skinnemoen 		goto err_init_slot;
182704d699c3SRob Emanuele 	}
18287d2be074SHaavard Skinnemoen 
1829965ebf33SHaavard Skinnemoen 	dev_info(&pdev->dev,
1830965ebf33SHaavard Skinnemoen 			"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
1831965ebf33SHaavard Skinnemoen 			host->mapbase, irq, nr_slots);
1832deec9ae3SHaavard Skinnemoen 
18337d2be074SHaavard Skinnemoen 	return 0;
18347d2be074SHaavard Skinnemoen 
1835965ebf33SHaavard Skinnemoen err_init_slot:
183665e8b083SHaavard Skinnemoen #ifdef CONFIG_MMC_ATMELMCI_DMA
183774465b4fSDan Williams 	if (host->dma.chan)
183874465b4fSDan Williams 		dma_release_channel(host->dma.chan);
183965e8b083SHaavard Skinnemoen #endif
1840965ebf33SHaavard Skinnemoen 	free_irq(irq, host);
18417d2be074SHaavard Skinnemoen err_request_irq:
18427d2be074SHaavard Skinnemoen 	iounmap(host->regs);
18437d2be074SHaavard Skinnemoen err_ioremap:
18447d2be074SHaavard Skinnemoen 	clk_put(host->mck);
18457d2be074SHaavard Skinnemoen err_clk_get:
1846965ebf33SHaavard Skinnemoen 	kfree(host);
18477d2be074SHaavard Skinnemoen 	return ret;
18487d2be074SHaavard Skinnemoen }
18497d2be074SHaavard Skinnemoen 
18507d2be074SHaavard Skinnemoen static int __exit atmci_remove(struct platform_device *pdev)
18517d2be074SHaavard Skinnemoen {
18527d2be074SHaavard Skinnemoen 	struct atmel_mci	*host = platform_get_drvdata(pdev);
1853965ebf33SHaavard Skinnemoen 	unsigned int		i;
18547d2be074SHaavard Skinnemoen 
18557d2be074SHaavard Skinnemoen 	platform_set_drvdata(pdev, NULL);
18567d2be074SHaavard Skinnemoen 
1857965ebf33SHaavard Skinnemoen 	for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
1858965ebf33SHaavard Skinnemoen 		if (host->slot[i])
1859965ebf33SHaavard Skinnemoen 			atmci_cleanup_slot(host->slot[i], i);
18607d2be074SHaavard Skinnemoen 	}
18617d2be074SHaavard Skinnemoen 
18627d2be074SHaavard Skinnemoen 	clk_enable(host->mck);
18637d2be074SHaavard Skinnemoen 	mci_writel(host, IDR, ~0UL);
18647d2be074SHaavard Skinnemoen 	mci_writel(host, CR, MCI_CR_MCIDIS);
18657d2be074SHaavard Skinnemoen 	mci_readl(host, SR);
18667d2be074SHaavard Skinnemoen 	clk_disable(host->mck);
18677d2be074SHaavard Skinnemoen 
186865e8b083SHaavard Skinnemoen #ifdef CONFIG_MMC_ATMELMCI_DMA
186974465b4fSDan Williams 	if (host->dma.chan)
187074465b4fSDan Williams 		dma_release_channel(host->dma.chan);
187165e8b083SHaavard Skinnemoen #endif
187265e8b083SHaavard Skinnemoen 
1873965ebf33SHaavard Skinnemoen 	free_irq(platform_get_irq(pdev, 0), host);
18747d2be074SHaavard Skinnemoen 	iounmap(host->regs);
18757d2be074SHaavard Skinnemoen 
18767d2be074SHaavard Skinnemoen 	clk_put(host->mck);
1877965ebf33SHaavard Skinnemoen 	kfree(host);
18787d2be074SHaavard Skinnemoen 
18797d2be074SHaavard Skinnemoen 	return 0;
18807d2be074SHaavard Skinnemoen }
18817d2be074SHaavard Skinnemoen 
18827d2be074SHaavard Skinnemoen static struct platform_driver atmci_driver = {
18837d2be074SHaavard Skinnemoen 	.remove		= __exit_p(atmci_remove),
18847d2be074SHaavard Skinnemoen 	.driver		= {
18857d2be074SHaavard Skinnemoen 		.name		= "atmel_mci",
18867d2be074SHaavard Skinnemoen 	},
18877d2be074SHaavard Skinnemoen };
18887d2be074SHaavard Skinnemoen 
18897d2be074SHaavard Skinnemoen static int __init atmci_init(void)
18907d2be074SHaavard Skinnemoen {
18917d2be074SHaavard Skinnemoen 	return platform_driver_probe(&atmci_driver, atmci_probe);
18927d2be074SHaavard Skinnemoen }
18937d2be074SHaavard Skinnemoen 
18947d2be074SHaavard Skinnemoen static void __exit atmci_exit(void)
18957d2be074SHaavard Skinnemoen {
18967d2be074SHaavard Skinnemoen 	platform_driver_unregister(&atmci_driver);
18977d2be074SHaavard Skinnemoen }
18987d2be074SHaavard Skinnemoen 
189974465b4fSDan Williams late_initcall(atmci_init); /* try to load after dma driver when built-in */
19007d2be074SHaavard Skinnemoen module_exit(atmci_exit);
19017d2be074SHaavard Skinnemoen 
19027d2be074SHaavard Skinnemoen MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
19037d2be074SHaavard Skinnemoen MODULE_AUTHOR("Haavard Skinnemoen <haavard.skinnemoen@atmel.com>");
19047d2be074SHaavard Skinnemoen MODULE_LICENSE("GPL v2");
1905