xref: /openbmc/linux/drivers/mmc/host/atmel-mci.c (revision fbd986cd)
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>
22e919fd20SLudovic Desroches #include <linux/of.h>
23e919fd20SLudovic Desroches #include <linux/of_device.h>
24e919fd20SLudovic Desroches #include <linux/of_gpio.h>
257d2be074SHaavard Skinnemoen #include <linux/platform_device.h>
267d2be074SHaavard Skinnemoen #include <linux/scatterlist.h>
27deec9ae3SHaavard Skinnemoen #include <linux/seq_file.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
29deec9ae3SHaavard Skinnemoen #include <linux/stat.h>
30e2b35f3dSViresh Kumar #include <linux/types.h>
31bcd2360cSJean-Christophe PLAGNIOL-VILLARD #include <linux/platform_data/atmel.h>
327d2be074SHaavard Skinnemoen 
337d2be074SHaavard Skinnemoen #include <linux/mmc/host.h>
342f1d7918SNicolas Ferre #include <linux/mmc/sdio.h>
352635d1baSNicolas Ferre 
362635d1baSNicolas Ferre #include <mach/atmel-mci.h>
37c42aa775SNicolas Ferre #include <linux/atmel-mci.h>
38796211b7SLudovic Desroches #include <linux/atmel_pdc.h>
397d2be074SHaavard Skinnemoen 
407d2be074SHaavard Skinnemoen #include <asm/io.h>
417d2be074SHaavard Skinnemoen #include <asm/unaligned.h>
427d2be074SHaavard Skinnemoen 
437d2be074SHaavard Skinnemoen #include "atmel-mci-regs.h"
447d2be074SHaavard Skinnemoen 
452c96a293SLudovic Desroches #define ATMCI_DATA_ERROR_FLAGS	(ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
4665e8b083SHaavard Skinnemoen #define ATMCI_DMA_THRESHOLD	16
477d2be074SHaavard Skinnemoen 
487d2be074SHaavard Skinnemoen enum {
49f5177547SLudovic Desroches 	EVENT_CMD_RDY = 0,
507d2be074SHaavard Skinnemoen 	EVENT_XFER_COMPLETE,
51f5177547SLudovic Desroches 	EVENT_NOTBUSY,
52c06ad258SHaavard Skinnemoen 	EVENT_DATA_ERROR,
53c06ad258SHaavard Skinnemoen };
54c06ad258SHaavard Skinnemoen 
55c06ad258SHaavard Skinnemoen enum atmel_mci_state {
56965ebf33SHaavard Skinnemoen 	STATE_IDLE = 0,
57965ebf33SHaavard Skinnemoen 	STATE_SENDING_CMD,
58f5177547SLudovic Desroches 	STATE_DATA_XFER,
59f5177547SLudovic Desroches 	STATE_WAITING_NOTBUSY,
60c06ad258SHaavard Skinnemoen 	STATE_SENDING_STOP,
61f5177547SLudovic Desroches 	STATE_END_REQUEST,
627d2be074SHaavard Skinnemoen };
637d2be074SHaavard Skinnemoen 
64796211b7SLudovic Desroches enum atmci_xfer_dir {
65796211b7SLudovic Desroches 	XFER_RECEIVE = 0,
66796211b7SLudovic Desroches 	XFER_TRANSMIT,
67796211b7SLudovic Desroches };
68796211b7SLudovic Desroches 
69796211b7SLudovic Desroches enum atmci_pdc_buf {
70796211b7SLudovic Desroches 	PDC_FIRST_BUF = 0,
71796211b7SLudovic Desroches 	PDC_SECOND_BUF,
72796211b7SLudovic Desroches };
73796211b7SLudovic Desroches 
74796211b7SLudovic Desroches struct atmel_mci_caps {
75ccdfe612SHein_Tibosch 	bool    has_dma_conf_reg;
76796211b7SLudovic Desroches 	bool    has_pdc;
77796211b7SLudovic Desroches 	bool    has_cfg_reg;
78796211b7SLudovic Desroches 	bool    has_cstor_reg;
79796211b7SLudovic Desroches 	bool    has_highspeed;
80796211b7SLudovic Desroches 	bool    has_rwproof;
81faf8180bSLudovic Desroches 	bool	has_odd_clk_div;
8224011f34SLudovic Desroches 	bool	has_bad_data_ordering;
8324011f34SLudovic Desroches 	bool	need_reset_after_xfer;
8424011f34SLudovic Desroches 	bool	need_blksz_mul_4;
85077d4073SLudovic Desroches 	bool	need_notbusy_for_read_ops;
86796211b7SLudovic Desroches };
87796211b7SLudovic Desroches 
8865e8b083SHaavard Skinnemoen struct atmel_mci_dma {
8965e8b083SHaavard Skinnemoen 	struct dma_chan			*chan;
9065e8b083SHaavard Skinnemoen 	struct dma_async_tx_descriptor	*data_desc;
9165e8b083SHaavard Skinnemoen };
9265e8b083SHaavard Skinnemoen 
93965ebf33SHaavard Skinnemoen /**
94965ebf33SHaavard Skinnemoen  * struct atmel_mci - MMC controller state shared between all slots
95965ebf33SHaavard Skinnemoen  * @lock: Spinlock protecting the queue and associated data.
96965ebf33SHaavard Skinnemoen  * @regs: Pointer to MMIO registers.
97796211b7SLudovic Desroches  * @sg: Scatterlist entry currently being processed by PIO or PDC code.
98965ebf33SHaavard Skinnemoen  * @pio_offset: Offset into the current scatterlist entry.
997a90dcc2SLudovic Desroches  * @buffer: Buffer used if we don't have the r/w proof capability. We
1007a90dcc2SLudovic Desroches  *      don't have the time to switch pdc buffers so we have to use only
1017a90dcc2SLudovic Desroches  *      one buffer for the full transaction.
1027a90dcc2SLudovic Desroches  * @buf_size: size of the buffer.
1037a90dcc2SLudovic Desroches  * @phys_buf_addr: buffer address needed for pdc.
104965ebf33SHaavard Skinnemoen  * @cur_slot: The slot which is currently using the controller.
105965ebf33SHaavard Skinnemoen  * @mrq: The request currently being processed on @cur_slot,
106965ebf33SHaavard Skinnemoen  *	or NULL if the controller is idle.
107965ebf33SHaavard Skinnemoen  * @cmd: The command currently being sent to the card, or NULL.
108965ebf33SHaavard Skinnemoen  * @data: The data currently being transferred, or NULL if no data
109965ebf33SHaavard Skinnemoen  *	transfer is in progress.
110796211b7SLudovic Desroches  * @data_size: just data->blocks * data->blksz.
11165e8b083SHaavard Skinnemoen  * @dma: DMA client state.
11265e8b083SHaavard Skinnemoen  * @data_chan: DMA channel being used for the current data transfer.
113965ebf33SHaavard Skinnemoen  * @cmd_status: Snapshot of SR taken upon completion of the current
114965ebf33SHaavard Skinnemoen  *	command. Only valid when EVENT_CMD_COMPLETE is pending.
115965ebf33SHaavard Skinnemoen  * @data_status: Snapshot of SR taken upon completion of the current
116965ebf33SHaavard Skinnemoen  *	data transfer. Only valid when EVENT_DATA_COMPLETE or
117965ebf33SHaavard Skinnemoen  *	EVENT_DATA_ERROR is pending.
118965ebf33SHaavard Skinnemoen  * @stop_cmdr: Value to be loaded into CMDR when the stop command is
119965ebf33SHaavard Skinnemoen  *	to be sent.
120965ebf33SHaavard Skinnemoen  * @tasklet: Tasklet running the request state machine.
121965ebf33SHaavard Skinnemoen  * @pending_events: Bitmask of events flagged by the interrupt handler
122965ebf33SHaavard Skinnemoen  *	to be processed by the tasklet.
123965ebf33SHaavard Skinnemoen  * @completed_events: Bitmask of events which the state machine has
124965ebf33SHaavard Skinnemoen  *	processed.
125965ebf33SHaavard Skinnemoen  * @state: Tasklet state.
126965ebf33SHaavard Skinnemoen  * @queue: List of slots waiting for access to the controller.
127965ebf33SHaavard Skinnemoen  * @need_clock_update: Update the clock rate before the next request.
128965ebf33SHaavard Skinnemoen  * @need_reset: Reset controller before next request.
12924011f34SLudovic Desroches  * @timer: Timer to balance the data timeout error flag which cannot rise.
130965ebf33SHaavard Skinnemoen  * @mode_reg: Value of the MR register.
13174791a2dSNicolas Ferre  * @cfg_reg: Value of the CFG register.
132965ebf33SHaavard Skinnemoen  * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
133965ebf33SHaavard Skinnemoen  *	rate and timeout calculations.
134965ebf33SHaavard Skinnemoen  * @mapbase: Physical address of the MMIO registers.
135965ebf33SHaavard Skinnemoen  * @mck: The peripheral bus clock hooked up to the MMC controller.
136965ebf33SHaavard Skinnemoen  * @pdev: Platform device associated with the MMC controller.
137965ebf33SHaavard Skinnemoen  * @slot: Slots sharing this MMC controller.
138796211b7SLudovic Desroches  * @caps: MCI capabilities depending on MCI version.
139796211b7SLudovic Desroches  * @prepare_data: function to setup MCI before data transfer which
140796211b7SLudovic Desroches  * depends on MCI capabilities.
141796211b7SLudovic Desroches  * @submit_data: function to start data transfer which depends on MCI
142796211b7SLudovic Desroches  * capabilities.
143796211b7SLudovic Desroches  * @stop_transfer: function to stop data transfer which depends on MCI
144796211b7SLudovic Desroches  * capabilities.
145965ebf33SHaavard Skinnemoen  *
146965ebf33SHaavard Skinnemoen  * Locking
147965ebf33SHaavard Skinnemoen  * =======
148965ebf33SHaavard Skinnemoen  *
149965ebf33SHaavard Skinnemoen  * @lock is a softirq-safe spinlock protecting @queue as well as
150965ebf33SHaavard Skinnemoen  * @cur_slot, @mrq and @state. These must always be updated
151965ebf33SHaavard Skinnemoen  * at the same time while holding @lock.
152965ebf33SHaavard Skinnemoen  *
153965ebf33SHaavard Skinnemoen  * @lock also protects mode_reg and need_clock_update since these are
154965ebf33SHaavard Skinnemoen  * used to synchronize mode register updates with the queue
155965ebf33SHaavard Skinnemoen  * processing.
156965ebf33SHaavard Skinnemoen  *
157965ebf33SHaavard Skinnemoen  * The @mrq field of struct atmel_mci_slot is also protected by @lock,
158965ebf33SHaavard Skinnemoen  * and must always be written at the same time as the slot is added to
159965ebf33SHaavard Skinnemoen  * @queue.
160965ebf33SHaavard Skinnemoen  *
161965ebf33SHaavard Skinnemoen  * @pending_events and @completed_events are accessed using atomic bit
162965ebf33SHaavard Skinnemoen  * operations, so they don't need any locking.
163965ebf33SHaavard Skinnemoen  *
164965ebf33SHaavard Skinnemoen  * None of the fields touched by the interrupt handler need any
165965ebf33SHaavard Skinnemoen  * locking. However, ordering is important: Before EVENT_DATA_ERROR or
166965ebf33SHaavard Skinnemoen  * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
167965ebf33SHaavard Skinnemoen  * interrupts must be disabled and @data_status updated with a
168965ebf33SHaavard Skinnemoen  * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
16925985edcSLucas De Marchi  * CMDRDY interrupt must be disabled and @cmd_status updated with a
170965ebf33SHaavard Skinnemoen  * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
171965ebf33SHaavard Skinnemoen  * bytes_xfered field of @data must be written. This is ensured by
172965ebf33SHaavard Skinnemoen  * using barriers.
173965ebf33SHaavard Skinnemoen  */
1747d2be074SHaavard Skinnemoen struct atmel_mci {
175965ebf33SHaavard Skinnemoen 	spinlock_t		lock;
1767d2be074SHaavard Skinnemoen 	void __iomem		*regs;
1777d2be074SHaavard Skinnemoen 
1787d2be074SHaavard Skinnemoen 	struct scatterlist	*sg;
179bdbc5d0cSTerry Barnaby 	unsigned int		sg_len;
1807d2be074SHaavard Skinnemoen 	unsigned int		pio_offset;
1817a90dcc2SLudovic Desroches 	unsigned int		*buffer;
1827a90dcc2SLudovic Desroches 	unsigned int		buf_size;
1837a90dcc2SLudovic Desroches 	dma_addr_t		buf_phys_addr;
1847d2be074SHaavard Skinnemoen 
185965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*cur_slot;
1867d2be074SHaavard Skinnemoen 	struct mmc_request	*mrq;
1877d2be074SHaavard Skinnemoen 	struct mmc_command	*cmd;
1887d2be074SHaavard Skinnemoen 	struct mmc_data		*data;
189796211b7SLudovic Desroches 	unsigned int		data_size;
1907d2be074SHaavard Skinnemoen 
19165e8b083SHaavard Skinnemoen 	struct atmel_mci_dma	dma;
19265e8b083SHaavard Skinnemoen 	struct dma_chan		*data_chan;
193e2b35f3dSViresh Kumar 	struct dma_slave_config	dma_conf;
19465e8b083SHaavard Skinnemoen 
1957d2be074SHaavard Skinnemoen 	u32			cmd_status;
1967d2be074SHaavard Skinnemoen 	u32			data_status;
1977d2be074SHaavard Skinnemoen 	u32			stop_cmdr;
1987d2be074SHaavard Skinnemoen 
1997d2be074SHaavard Skinnemoen 	struct tasklet_struct	tasklet;
2007d2be074SHaavard Skinnemoen 	unsigned long		pending_events;
2017d2be074SHaavard Skinnemoen 	unsigned long		completed_events;
202c06ad258SHaavard Skinnemoen 	enum atmel_mci_state	state;
203965ebf33SHaavard Skinnemoen 	struct list_head	queue;
2047d2be074SHaavard Skinnemoen 
205965ebf33SHaavard Skinnemoen 	bool			need_clock_update;
206965ebf33SHaavard Skinnemoen 	bool			need_reset;
20724011f34SLudovic Desroches 	struct timer_list	timer;
208965ebf33SHaavard Skinnemoen 	u32			mode_reg;
20974791a2dSNicolas Ferre 	u32			cfg_reg;
2107d2be074SHaavard Skinnemoen 	unsigned long		bus_hz;
2117d2be074SHaavard Skinnemoen 	unsigned long		mapbase;
2127d2be074SHaavard Skinnemoen 	struct clk		*mck;
2137d2be074SHaavard Skinnemoen 	struct platform_device	*pdev;
214965ebf33SHaavard Skinnemoen 
2152c96a293SLudovic Desroches 	struct atmel_mci_slot	*slot[ATMCI_MAX_NR_SLOTS];
216796211b7SLudovic Desroches 
217796211b7SLudovic Desroches 	struct atmel_mci_caps   caps;
218796211b7SLudovic Desroches 
219796211b7SLudovic Desroches 	u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data);
220796211b7SLudovic Desroches 	void (*submit_data)(struct atmel_mci *host, struct mmc_data *data);
221796211b7SLudovic Desroches 	void (*stop_transfer)(struct atmel_mci *host);
222965ebf33SHaavard Skinnemoen };
223965ebf33SHaavard Skinnemoen 
224965ebf33SHaavard Skinnemoen /**
225965ebf33SHaavard Skinnemoen  * struct atmel_mci_slot - MMC slot state
226965ebf33SHaavard Skinnemoen  * @mmc: The mmc_host representing this slot.
227965ebf33SHaavard Skinnemoen  * @host: The MMC controller this slot is using.
228965ebf33SHaavard Skinnemoen  * @sdc_reg: Value of SDCR to be written before using this slot.
22988ff82edSAnders Grahn  * @sdio_irq: SDIO irq mask for this slot.
230965ebf33SHaavard Skinnemoen  * @mrq: mmc_request currently being processed or waiting to be
231965ebf33SHaavard Skinnemoen  *	processed, or NULL when the slot is idle.
232965ebf33SHaavard Skinnemoen  * @queue_node: List node for placing this node in the @queue list of
233965ebf33SHaavard Skinnemoen  *	&struct atmel_mci.
234965ebf33SHaavard Skinnemoen  * @clock: Clock rate configured by set_ios(). Protected by host->lock.
235965ebf33SHaavard Skinnemoen  * @flags: Random state bits associated with the slot.
236965ebf33SHaavard Skinnemoen  * @detect_pin: GPIO pin used for card detection, or negative if not
237965ebf33SHaavard Skinnemoen  *	available.
238965ebf33SHaavard Skinnemoen  * @wp_pin: GPIO pin used for card write protect sending, or negative
239965ebf33SHaavard Skinnemoen  *	if not available.
2401c1452beSJonas Larsson  * @detect_is_active_high: The state of the detect pin when it is active.
241965ebf33SHaavard Skinnemoen  * @detect_timer: Timer used for debouncing @detect_pin interrupts.
242965ebf33SHaavard Skinnemoen  */
243965ebf33SHaavard Skinnemoen struct atmel_mci_slot {
244965ebf33SHaavard Skinnemoen 	struct mmc_host		*mmc;
245965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host;
246965ebf33SHaavard Skinnemoen 
247965ebf33SHaavard Skinnemoen 	u32			sdc_reg;
24888ff82edSAnders Grahn 	u32			sdio_irq;
249965ebf33SHaavard Skinnemoen 
250965ebf33SHaavard Skinnemoen 	struct mmc_request	*mrq;
251965ebf33SHaavard Skinnemoen 	struct list_head	queue_node;
252965ebf33SHaavard Skinnemoen 
253965ebf33SHaavard Skinnemoen 	unsigned int		clock;
254965ebf33SHaavard Skinnemoen 	unsigned long		flags;
255965ebf33SHaavard Skinnemoen #define ATMCI_CARD_PRESENT	0
256965ebf33SHaavard Skinnemoen #define ATMCI_CARD_NEED_INIT	1
257965ebf33SHaavard Skinnemoen #define ATMCI_SHUTDOWN		2
2585c2f2b9bSNicolas Ferre #define ATMCI_SUSPENDED		3
259965ebf33SHaavard Skinnemoen 
260965ebf33SHaavard Skinnemoen 	int			detect_pin;
261965ebf33SHaavard Skinnemoen 	int			wp_pin;
2621c1452beSJonas Larsson 	bool			detect_is_active_high;
263965ebf33SHaavard Skinnemoen 
264965ebf33SHaavard Skinnemoen 	struct timer_list	detect_timer;
2657d2be074SHaavard Skinnemoen };
2667d2be074SHaavard Skinnemoen 
2677d2be074SHaavard Skinnemoen #define atmci_test_and_clear_pending(host, event)		\
2687d2be074SHaavard Skinnemoen 	test_and_clear_bit(event, &host->pending_events)
2697d2be074SHaavard Skinnemoen #define atmci_set_completed(host, event)			\
2707d2be074SHaavard Skinnemoen 	set_bit(event, &host->completed_events)
2717d2be074SHaavard Skinnemoen #define atmci_set_pending(host, event)				\
2727d2be074SHaavard Skinnemoen 	set_bit(event, &host->pending_events)
2737d2be074SHaavard Skinnemoen 
274deec9ae3SHaavard Skinnemoen /*
275deec9ae3SHaavard Skinnemoen  * The debugfs stuff below is mostly optimized away when
276deec9ae3SHaavard Skinnemoen  * CONFIG_DEBUG_FS is not set.
277deec9ae3SHaavard Skinnemoen  */
278deec9ae3SHaavard Skinnemoen static int atmci_req_show(struct seq_file *s, void *v)
279deec9ae3SHaavard Skinnemoen {
280965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = s->private;
281965ebf33SHaavard Skinnemoen 	struct mmc_request	*mrq;
282deec9ae3SHaavard Skinnemoen 	struct mmc_command	*cmd;
283deec9ae3SHaavard Skinnemoen 	struct mmc_command	*stop;
284deec9ae3SHaavard Skinnemoen 	struct mmc_data		*data;
285deec9ae3SHaavard Skinnemoen 
286deec9ae3SHaavard Skinnemoen 	/* Make sure we get a consistent snapshot */
287965ebf33SHaavard Skinnemoen 	spin_lock_bh(&slot->host->lock);
288965ebf33SHaavard Skinnemoen 	mrq = slot->mrq;
289deec9ae3SHaavard Skinnemoen 
290deec9ae3SHaavard Skinnemoen 	if (mrq) {
291deec9ae3SHaavard Skinnemoen 		cmd = mrq->cmd;
292deec9ae3SHaavard Skinnemoen 		data = mrq->data;
293deec9ae3SHaavard Skinnemoen 		stop = mrq->stop;
294deec9ae3SHaavard Skinnemoen 
295deec9ae3SHaavard Skinnemoen 		if (cmd)
296deec9ae3SHaavard Skinnemoen 			seq_printf(s,
297deec9ae3SHaavard Skinnemoen 				"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
298deec9ae3SHaavard Skinnemoen 				cmd->opcode, cmd->arg, cmd->flags,
299deec9ae3SHaavard Skinnemoen 				cmd->resp[0], cmd->resp[1], cmd->resp[2],
300d586ebbbSNicolas Ferre 				cmd->resp[3], cmd->error);
301deec9ae3SHaavard Skinnemoen 		if (data)
302deec9ae3SHaavard Skinnemoen 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
303deec9ae3SHaavard Skinnemoen 				data->bytes_xfered, data->blocks,
304deec9ae3SHaavard Skinnemoen 				data->blksz, data->flags, data->error);
305deec9ae3SHaavard Skinnemoen 		if (stop)
306deec9ae3SHaavard Skinnemoen 			seq_printf(s,
307deec9ae3SHaavard Skinnemoen 				"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
308deec9ae3SHaavard Skinnemoen 				stop->opcode, stop->arg, stop->flags,
309deec9ae3SHaavard Skinnemoen 				stop->resp[0], stop->resp[1], stop->resp[2],
310d586ebbbSNicolas Ferre 				stop->resp[3], stop->error);
311deec9ae3SHaavard Skinnemoen 	}
312deec9ae3SHaavard Skinnemoen 
313965ebf33SHaavard Skinnemoen 	spin_unlock_bh(&slot->host->lock);
314deec9ae3SHaavard Skinnemoen 
315deec9ae3SHaavard Skinnemoen 	return 0;
316deec9ae3SHaavard Skinnemoen }
317deec9ae3SHaavard Skinnemoen 
318deec9ae3SHaavard Skinnemoen static int atmci_req_open(struct inode *inode, struct file *file)
319deec9ae3SHaavard Skinnemoen {
320deec9ae3SHaavard Skinnemoen 	return single_open(file, atmci_req_show, inode->i_private);
321deec9ae3SHaavard Skinnemoen }
322deec9ae3SHaavard Skinnemoen 
323deec9ae3SHaavard Skinnemoen static const struct file_operations atmci_req_fops = {
324deec9ae3SHaavard Skinnemoen 	.owner		= THIS_MODULE,
325deec9ae3SHaavard Skinnemoen 	.open		= atmci_req_open,
326deec9ae3SHaavard Skinnemoen 	.read		= seq_read,
327deec9ae3SHaavard Skinnemoen 	.llseek		= seq_lseek,
328deec9ae3SHaavard Skinnemoen 	.release	= single_release,
329deec9ae3SHaavard Skinnemoen };
330deec9ae3SHaavard Skinnemoen 
331deec9ae3SHaavard Skinnemoen static void atmci_show_status_reg(struct seq_file *s,
332deec9ae3SHaavard Skinnemoen 		const char *regname, u32 value)
333deec9ae3SHaavard Skinnemoen {
334deec9ae3SHaavard Skinnemoen 	static const char	*sr_bit[] = {
335deec9ae3SHaavard Skinnemoen 		[0]	= "CMDRDY",
336deec9ae3SHaavard Skinnemoen 		[1]	= "RXRDY",
337deec9ae3SHaavard Skinnemoen 		[2]	= "TXRDY",
338deec9ae3SHaavard Skinnemoen 		[3]	= "BLKE",
339deec9ae3SHaavard Skinnemoen 		[4]	= "DTIP",
340deec9ae3SHaavard Skinnemoen 		[5]	= "NOTBUSY",
34104d699c3SRob Emanuele 		[6]	= "ENDRX",
34204d699c3SRob Emanuele 		[7]	= "ENDTX",
343deec9ae3SHaavard Skinnemoen 		[8]	= "SDIOIRQA",
344deec9ae3SHaavard Skinnemoen 		[9]	= "SDIOIRQB",
34504d699c3SRob Emanuele 		[12]	= "SDIOWAIT",
34604d699c3SRob Emanuele 		[14]	= "RXBUFF",
34704d699c3SRob Emanuele 		[15]	= "TXBUFE",
348deec9ae3SHaavard Skinnemoen 		[16]	= "RINDE",
349deec9ae3SHaavard Skinnemoen 		[17]	= "RDIRE",
350deec9ae3SHaavard Skinnemoen 		[18]	= "RCRCE",
351deec9ae3SHaavard Skinnemoen 		[19]	= "RENDE",
352deec9ae3SHaavard Skinnemoen 		[20]	= "RTOE",
353deec9ae3SHaavard Skinnemoen 		[21]	= "DCRCE",
354deec9ae3SHaavard Skinnemoen 		[22]	= "DTOE",
35504d699c3SRob Emanuele 		[23]	= "CSTOE",
35604d699c3SRob Emanuele 		[24]	= "BLKOVRE",
35704d699c3SRob Emanuele 		[25]	= "DMADONE",
35804d699c3SRob Emanuele 		[26]	= "FIFOEMPTY",
35904d699c3SRob Emanuele 		[27]	= "XFRDONE",
360deec9ae3SHaavard Skinnemoen 		[30]	= "OVRE",
361deec9ae3SHaavard Skinnemoen 		[31]	= "UNRE",
362deec9ae3SHaavard Skinnemoen 	};
363deec9ae3SHaavard Skinnemoen 	unsigned int		i;
364deec9ae3SHaavard Skinnemoen 
365deec9ae3SHaavard Skinnemoen 	seq_printf(s, "%s:\t0x%08x", regname, value);
366deec9ae3SHaavard Skinnemoen 	for (i = 0; i < ARRAY_SIZE(sr_bit); i++) {
367deec9ae3SHaavard Skinnemoen 		if (value & (1 << i)) {
368deec9ae3SHaavard Skinnemoen 			if (sr_bit[i])
369deec9ae3SHaavard Skinnemoen 				seq_printf(s, " %s", sr_bit[i]);
370deec9ae3SHaavard Skinnemoen 			else
371deec9ae3SHaavard Skinnemoen 				seq_puts(s, " UNKNOWN");
372deec9ae3SHaavard Skinnemoen 		}
373deec9ae3SHaavard Skinnemoen 	}
374deec9ae3SHaavard Skinnemoen 	seq_putc(s, '\n');
375deec9ae3SHaavard Skinnemoen }
376deec9ae3SHaavard Skinnemoen 
377deec9ae3SHaavard Skinnemoen static int atmci_regs_show(struct seq_file *s, void *v)
378deec9ae3SHaavard Skinnemoen {
379deec9ae3SHaavard Skinnemoen 	struct atmel_mci	*host = s->private;
380deec9ae3SHaavard Skinnemoen 	u32			*buf;
381b3894f26SBoris BREZILLON 	int			ret = 0;
382b3894f26SBoris BREZILLON 
383deec9ae3SHaavard Skinnemoen 
3842c96a293SLudovic Desroches 	buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL);
385deec9ae3SHaavard Skinnemoen 	if (!buf)
386deec9ae3SHaavard Skinnemoen 		return -ENOMEM;
387deec9ae3SHaavard Skinnemoen 
388965ebf33SHaavard Skinnemoen 	/*
389965ebf33SHaavard Skinnemoen 	 * Grab a more or less consistent snapshot. Note that we're
390965ebf33SHaavard Skinnemoen 	 * not disabling interrupts, so IMR and SR may not be
391965ebf33SHaavard Skinnemoen 	 * consistent.
392965ebf33SHaavard Skinnemoen 	 */
393b3894f26SBoris BREZILLON 	ret = clk_prepare_enable(host->mck);
394b3894f26SBoris BREZILLON 	if (ret)
395b3894f26SBoris BREZILLON 		goto out;
396b3894f26SBoris BREZILLON 
397965ebf33SHaavard Skinnemoen 	spin_lock_bh(&host->lock);
3982c96a293SLudovic Desroches 	memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
399965ebf33SHaavard Skinnemoen 	spin_unlock_bh(&host->lock);
400deec9ae3SHaavard Skinnemoen 
401b3894f26SBoris BREZILLON 	clk_disable_unprepare(host->mck);
402b3894f26SBoris BREZILLON 
4038a4de07eSNicolas Ferre 	seq_printf(s, "MR:\t0x%08x%s%s ",
4042c96a293SLudovic Desroches 			buf[ATMCI_MR / 4],
4052c96a293SLudovic Desroches 			buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
4068a4de07eSNicolas Ferre 			buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "");
4078a4de07eSNicolas Ferre 	if (host->caps.has_odd_clk_div)
4088a4de07eSNicolas Ferre 		seq_printf(s, "{CLKDIV,CLKODD}=%u\n",
4098a4de07eSNicolas Ferre 				((buf[ATMCI_MR / 4] & 0xff) << 1)
4108a4de07eSNicolas Ferre 				| ((buf[ATMCI_MR / 4] >> 16) & 1));
4118a4de07eSNicolas Ferre 	else
4128a4de07eSNicolas Ferre 		seq_printf(s, "CLKDIV=%u\n",
4138a4de07eSNicolas Ferre 				(buf[ATMCI_MR / 4] & 0xff));
4142c96a293SLudovic Desroches 	seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
4152c96a293SLudovic Desroches 	seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
4162c96a293SLudovic Desroches 	seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
417deec9ae3SHaavard Skinnemoen 	seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n",
4182c96a293SLudovic Desroches 			buf[ATMCI_BLKR / 4],
4192c96a293SLudovic Desroches 			buf[ATMCI_BLKR / 4] & 0xffff,
4202c96a293SLudovic Desroches 			(buf[ATMCI_BLKR / 4] >> 16) & 0xffff);
421796211b7SLudovic Desroches 	if (host->caps.has_cstor_reg)
4222c96a293SLudovic Desroches 		seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]);
423deec9ae3SHaavard Skinnemoen 
424deec9ae3SHaavard Skinnemoen 	/* Don't read RSPR and RDR; it will consume the data there */
425deec9ae3SHaavard Skinnemoen 
4262c96a293SLudovic Desroches 	atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]);
4272c96a293SLudovic Desroches 	atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]);
428deec9ae3SHaavard Skinnemoen 
429ccdfe612SHein_Tibosch 	if (host->caps.has_dma_conf_reg) {
43074791a2dSNicolas Ferre 		u32 val;
43174791a2dSNicolas Ferre 
4322c96a293SLudovic Desroches 		val = buf[ATMCI_DMA / 4];
43374791a2dSNicolas Ferre 		seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n",
43474791a2dSNicolas Ferre 				val, val & 3,
43574791a2dSNicolas Ferre 				((val >> 4) & 3) ?
43674791a2dSNicolas Ferre 					1 << (((val >> 4) & 3) + 1) : 1,
4372c96a293SLudovic Desroches 				val & ATMCI_DMAEN ? " DMAEN" : "");
438796211b7SLudovic Desroches 	}
439796211b7SLudovic Desroches 	if (host->caps.has_cfg_reg) {
440796211b7SLudovic Desroches 		u32 val;
44174791a2dSNicolas Ferre 
4422c96a293SLudovic Desroches 		val = buf[ATMCI_CFG / 4];
44374791a2dSNicolas Ferre 		seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n",
44474791a2dSNicolas Ferre 				val,
4452c96a293SLudovic Desroches 				val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "",
4462c96a293SLudovic Desroches 				val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "",
4472c96a293SLudovic Desroches 				val & ATMCI_CFG_HSMODE ? " HSMODE" : "",
4482c96a293SLudovic Desroches 				val & ATMCI_CFG_LSYNC ? " LSYNC" : "");
44974791a2dSNicolas Ferre 	}
45074791a2dSNicolas Ferre 
451b3894f26SBoris BREZILLON out:
452b17339a1SHaavard Skinnemoen 	kfree(buf);
453b17339a1SHaavard Skinnemoen 
454b3894f26SBoris BREZILLON 	return ret;
455deec9ae3SHaavard Skinnemoen }
456deec9ae3SHaavard Skinnemoen 
457deec9ae3SHaavard Skinnemoen static int atmci_regs_open(struct inode *inode, struct file *file)
458deec9ae3SHaavard Skinnemoen {
459deec9ae3SHaavard Skinnemoen 	return single_open(file, atmci_regs_show, inode->i_private);
460deec9ae3SHaavard Skinnemoen }
461deec9ae3SHaavard Skinnemoen 
462deec9ae3SHaavard Skinnemoen static const struct file_operations atmci_regs_fops = {
463deec9ae3SHaavard Skinnemoen 	.owner		= THIS_MODULE,
464deec9ae3SHaavard Skinnemoen 	.open		= atmci_regs_open,
465deec9ae3SHaavard Skinnemoen 	.read		= seq_read,
466deec9ae3SHaavard Skinnemoen 	.llseek		= seq_lseek,
467deec9ae3SHaavard Skinnemoen 	.release	= single_release,
468deec9ae3SHaavard Skinnemoen };
469deec9ae3SHaavard Skinnemoen 
470965ebf33SHaavard Skinnemoen static void atmci_init_debugfs(struct atmel_mci_slot *slot)
471deec9ae3SHaavard Skinnemoen {
472965ebf33SHaavard Skinnemoen 	struct mmc_host		*mmc = slot->mmc;
473965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = slot->host;
474deec9ae3SHaavard Skinnemoen 	struct dentry		*root;
475deec9ae3SHaavard Skinnemoen 	struct dentry		*node;
476deec9ae3SHaavard Skinnemoen 
477deec9ae3SHaavard Skinnemoen 	root = mmc->debugfs_root;
478deec9ae3SHaavard Skinnemoen 	if (!root)
479deec9ae3SHaavard Skinnemoen 		return;
480deec9ae3SHaavard Skinnemoen 
481deec9ae3SHaavard Skinnemoen 	node = debugfs_create_file("regs", S_IRUSR, root, host,
482deec9ae3SHaavard Skinnemoen 			&atmci_regs_fops);
483deec9ae3SHaavard Skinnemoen 	if (IS_ERR(node))
484deec9ae3SHaavard Skinnemoen 		return;
485deec9ae3SHaavard Skinnemoen 	if (!node)
486deec9ae3SHaavard Skinnemoen 		goto err;
487deec9ae3SHaavard Skinnemoen 
488965ebf33SHaavard Skinnemoen 	node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
489deec9ae3SHaavard Skinnemoen 	if (!node)
490deec9ae3SHaavard Skinnemoen 		goto err;
491deec9ae3SHaavard Skinnemoen 
492c06ad258SHaavard Skinnemoen 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
493c06ad258SHaavard Skinnemoen 	if (!node)
494c06ad258SHaavard Skinnemoen 		goto err;
495c06ad258SHaavard Skinnemoen 
496deec9ae3SHaavard Skinnemoen 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
497deec9ae3SHaavard Skinnemoen 				     (u32 *)&host->pending_events);
498deec9ae3SHaavard Skinnemoen 	if (!node)
499deec9ae3SHaavard Skinnemoen 		goto err;
500deec9ae3SHaavard Skinnemoen 
501deec9ae3SHaavard Skinnemoen 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
502deec9ae3SHaavard Skinnemoen 				     (u32 *)&host->completed_events);
503deec9ae3SHaavard Skinnemoen 	if (!node)
504deec9ae3SHaavard Skinnemoen 		goto err;
505deec9ae3SHaavard Skinnemoen 
506deec9ae3SHaavard Skinnemoen 	return;
507deec9ae3SHaavard Skinnemoen 
508deec9ae3SHaavard Skinnemoen err:
509965ebf33SHaavard Skinnemoen 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
510deec9ae3SHaavard Skinnemoen }
5117d2be074SHaavard Skinnemoen 
512e919fd20SLudovic Desroches #if defined(CONFIG_OF)
513e919fd20SLudovic Desroches static const struct of_device_id atmci_dt_ids[] = {
514e919fd20SLudovic Desroches 	{ .compatible = "atmel,hsmci" },
515e919fd20SLudovic Desroches 	{ /* sentinel */ }
516e919fd20SLudovic Desroches };
517e919fd20SLudovic Desroches 
518e919fd20SLudovic Desroches MODULE_DEVICE_TABLE(of, atmci_dt_ids);
519e919fd20SLudovic Desroches 
520c3be1efdSBill Pemberton static struct mci_platform_data*
521e919fd20SLudovic Desroches atmci_of_init(struct platform_device *pdev)
522e919fd20SLudovic Desroches {
523e919fd20SLudovic Desroches 	struct device_node *np = pdev->dev.of_node;
524e919fd20SLudovic Desroches 	struct device_node *cnp;
525e919fd20SLudovic Desroches 	struct mci_platform_data *pdata;
526e919fd20SLudovic Desroches 	u32 slot_id;
527e919fd20SLudovic Desroches 
528e919fd20SLudovic Desroches 	if (!np) {
529e919fd20SLudovic Desroches 		dev_err(&pdev->dev, "device node not found\n");
530e919fd20SLudovic Desroches 		return ERR_PTR(-EINVAL);
531e919fd20SLudovic Desroches 	}
532e919fd20SLudovic Desroches 
533e919fd20SLudovic Desroches 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
534e919fd20SLudovic Desroches 	if (!pdata) {
535e919fd20SLudovic Desroches 		dev_err(&pdev->dev, "could not allocate memory for pdata\n");
536e919fd20SLudovic Desroches 		return ERR_PTR(-ENOMEM);
537e919fd20SLudovic Desroches 	}
538e919fd20SLudovic Desroches 
539e919fd20SLudovic Desroches 	for_each_child_of_node(np, cnp) {
540e919fd20SLudovic Desroches 		if (of_property_read_u32(cnp, "reg", &slot_id)) {
541e919fd20SLudovic Desroches 			dev_warn(&pdev->dev, "reg property is missing for %s\n",
542e919fd20SLudovic Desroches 				 cnp->full_name);
543e919fd20SLudovic Desroches 			continue;
544e919fd20SLudovic Desroches 		}
545e919fd20SLudovic Desroches 
546e919fd20SLudovic Desroches 		if (slot_id >= ATMCI_MAX_NR_SLOTS) {
547e919fd20SLudovic Desroches 			dev_warn(&pdev->dev, "can't have more than %d slots\n",
548e919fd20SLudovic Desroches 			         ATMCI_MAX_NR_SLOTS);
549e919fd20SLudovic Desroches 			break;
550e919fd20SLudovic Desroches 		}
551e919fd20SLudovic Desroches 
552e919fd20SLudovic Desroches 		if (of_property_read_u32(cnp, "bus-width",
553e919fd20SLudovic Desroches 		                         &pdata->slot[slot_id].bus_width))
554e919fd20SLudovic Desroches 			pdata->slot[slot_id].bus_width = 1;
555e919fd20SLudovic Desroches 
556e919fd20SLudovic Desroches 		pdata->slot[slot_id].detect_pin =
557e919fd20SLudovic Desroches 			of_get_named_gpio(cnp, "cd-gpios", 0);
558e919fd20SLudovic Desroches 
559e919fd20SLudovic Desroches 		pdata->slot[slot_id].detect_is_active_high =
560e919fd20SLudovic Desroches 			of_property_read_bool(cnp, "cd-inverted");
561e919fd20SLudovic Desroches 
562e919fd20SLudovic Desroches 		pdata->slot[slot_id].wp_pin =
563e919fd20SLudovic Desroches 			of_get_named_gpio(cnp, "wp-gpios", 0);
564e919fd20SLudovic Desroches 	}
565e919fd20SLudovic Desroches 
566e919fd20SLudovic Desroches 	return pdata;
567e919fd20SLudovic Desroches }
568e919fd20SLudovic Desroches #else /* CONFIG_OF */
569e919fd20SLudovic Desroches static inline struct mci_platform_data*
570e919fd20SLudovic Desroches atmci_of_init(struct platform_device *dev)
571e919fd20SLudovic Desroches {
572e919fd20SLudovic Desroches 	return ERR_PTR(-EINVAL);
573e919fd20SLudovic Desroches }
574e919fd20SLudovic Desroches #endif
575e919fd20SLudovic Desroches 
5767a90dcc2SLudovic Desroches static inline unsigned int atmci_get_version(struct atmel_mci *host)
5777a90dcc2SLudovic Desroches {
5787a90dcc2SLudovic Desroches 	return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
5797a90dcc2SLudovic Desroches }
5807a90dcc2SLudovic Desroches 
58124011f34SLudovic Desroches static void atmci_timeout_timer(unsigned long data)
58224011f34SLudovic Desroches {
58324011f34SLudovic Desroches 	struct atmel_mci *host;
58424011f34SLudovic Desroches 
58524011f34SLudovic Desroches 	host = (struct atmel_mci *)data;
58624011f34SLudovic Desroches 
58724011f34SLudovic Desroches 	dev_dbg(&host->pdev->dev, "software timeout\n");
58824011f34SLudovic Desroches 
58924011f34SLudovic Desroches 	if (host->mrq->cmd->data) {
59024011f34SLudovic Desroches 		host->mrq->cmd->data->error = -ETIMEDOUT;
59124011f34SLudovic Desroches 		host->data = NULL;
592c1fa3426SLudovic Desroches 		/*
593c1fa3426SLudovic Desroches 		 * With some SDIO modules, sometimes DMA transfer hangs. If
594c1fa3426SLudovic Desroches 		 * stop_transfer() is not called then the DMA request is not
595c1fa3426SLudovic Desroches 		 * removed, following ones are queued and never computed.
596c1fa3426SLudovic Desroches 		 */
597c1fa3426SLudovic Desroches 		if (host->state == STATE_DATA_XFER)
598c1fa3426SLudovic Desroches 			host->stop_transfer(host);
59924011f34SLudovic Desroches 	} else {
60024011f34SLudovic Desroches 		host->mrq->cmd->error = -ETIMEDOUT;
60124011f34SLudovic Desroches 		host->cmd = NULL;
60224011f34SLudovic Desroches 	}
60324011f34SLudovic Desroches 	host->need_reset = 1;
60424011f34SLudovic Desroches 	host->state = STATE_END_REQUEST;
60524011f34SLudovic Desroches 	smp_wmb();
60624011f34SLudovic Desroches 	tasklet_schedule(&host->tasklet);
60724011f34SLudovic Desroches }
60824011f34SLudovic Desroches 
6092c96a293SLudovic Desroches static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
6107d2be074SHaavard Skinnemoen 					unsigned int ns)
6117d2be074SHaavard Skinnemoen {
61266292ad9SLudovic Desroches 	/*
61366292ad9SLudovic Desroches 	 * It is easier here to use us instead of ns for the timeout,
61466292ad9SLudovic Desroches 	 * it prevents from overflows during calculation.
61566292ad9SLudovic Desroches 	 */
61666292ad9SLudovic Desroches 	unsigned int us = DIV_ROUND_UP(ns, 1000);
61766292ad9SLudovic Desroches 
61866292ad9SLudovic Desroches 	/* Maximum clock frequency is host->bus_hz/2 */
61966292ad9SLudovic Desroches 	return us * (DIV_ROUND_UP(host->bus_hz, 2000000));
6207d2be074SHaavard Skinnemoen }
6217d2be074SHaavard Skinnemoen 
6227d2be074SHaavard Skinnemoen static void atmci_set_timeout(struct atmel_mci *host,
623965ebf33SHaavard Skinnemoen 		struct atmel_mci_slot *slot, struct mmc_data *data)
6247d2be074SHaavard Skinnemoen {
6257d2be074SHaavard Skinnemoen 	static unsigned	dtomul_to_shift[] = {
6267d2be074SHaavard Skinnemoen 		0, 4, 7, 8, 10, 12, 16, 20
6277d2be074SHaavard Skinnemoen 	};
6287d2be074SHaavard Skinnemoen 	unsigned	timeout;
6297d2be074SHaavard Skinnemoen 	unsigned	dtocyc;
6307d2be074SHaavard Skinnemoen 	unsigned	dtomul;
6317d2be074SHaavard Skinnemoen 
6322c96a293SLudovic Desroches 	timeout = atmci_ns_to_clocks(host, data->timeout_ns)
6332c96a293SLudovic Desroches 		+ data->timeout_clks;
6347d2be074SHaavard Skinnemoen 
6357d2be074SHaavard Skinnemoen 	for (dtomul = 0; dtomul < 8; dtomul++) {
6367d2be074SHaavard Skinnemoen 		unsigned shift = dtomul_to_shift[dtomul];
6377d2be074SHaavard Skinnemoen 		dtocyc = (timeout + (1 << shift) - 1) >> shift;
6387d2be074SHaavard Skinnemoen 		if (dtocyc < 15)
6397d2be074SHaavard Skinnemoen 			break;
6407d2be074SHaavard Skinnemoen 	}
6417d2be074SHaavard Skinnemoen 
6427d2be074SHaavard Skinnemoen 	if (dtomul >= 8) {
6437d2be074SHaavard Skinnemoen 		dtomul = 7;
6447d2be074SHaavard Skinnemoen 		dtocyc = 15;
6457d2be074SHaavard Skinnemoen 	}
6467d2be074SHaavard Skinnemoen 
647965ebf33SHaavard Skinnemoen 	dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
6487d2be074SHaavard Skinnemoen 			dtocyc << dtomul_to_shift[dtomul]);
64903fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc)));
6507d2be074SHaavard Skinnemoen }
6517d2be074SHaavard Skinnemoen 
6527d2be074SHaavard Skinnemoen /*
6537d2be074SHaavard Skinnemoen  * Return mask with command flags to be enabled for this command.
6547d2be074SHaavard Skinnemoen  */
6557d2be074SHaavard Skinnemoen static u32 atmci_prepare_command(struct mmc_host *mmc,
6567d2be074SHaavard Skinnemoen 				 struct mmc_command *cmd)
6577d2be074SHaavard Skinnemoen {
6587d2be074SHaavard Skinnemoen 	struct mmc_data	*data;
6597d2be074SHaavard Skinnemoen 	u32		cmdr;
6607d2be074SHaavard Skinnemoen 
6617d2be074SHaavard Skinnemoen 	cmd->error = -EINPROGRESS;
6627d2be074SHaavard Skinnemoen 
6632c96a293SLudovic Desroches 	cmdr = ATMCI_CMDR_CMDNB(cmd->opcode);
6647d2be074SHaavard Skinnemoen 
6657d2be074SHaavard Skinnemoen 	if (cmd->flags & MMC_RSP_PRESENT) {
6667d2be074SHaavard Skinnemoen 		if (cmd->flags & MMC_RSP_136)
6672c96a293SLudovic Desroches 			cmdr |= ATMCI_CMDR_RSPTYP_136BIT;
6687d2be074SHaavard Skinnemoen 		else
6692c96a293SLudovic Desroches 			cmdr |= ATMCI_CMDR_RSPTYP_48BIT;
6707d2be074SHaavard Skinnemoen 	}
6717d2be074SHaavard Skinnemoen 
6727d2be074SHaavard Skinnemoen 	/*
6737d2be074SHaavard Skinnemoen 	 * This should really be MAXLAT_5 for CMD2 and ACMD41, but
6747d2be074SHaavard Skinnemoen 	 * it's too difficult to determine whether this is an ACMD or
6757d2be074SHaavard Skinnemoen 	 * not. Better make it 64.
6767d2be074SHaavard Skinnemoen 	 */
6772c96a293SLudovic Desroches 	cmdr |= ATMCI_CMDR_MAXLAT_64CYC;
6787d2be074SHaavard Skinnemoen 
6797d2be074SHaavard Skinnemoen 	if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
6802c96a293SLudovic Desroches 		cmdr |= ATMCI_CMDR_OPDCMD;
6817d2be074SHaavard Skinnemoen 
6827d2be074SHaavard Skinnemoen 	data = cmd->data;
6837d2be074SHaavard Skinnemoen 	if (data) {
6842c96a293SLudovic Desroches 		cmdr |= ATMCI_CMDR_START_XFER;
6852f1d7918SNicolas Ferre 
6862f1d7918SNicolas Ferre 		if (cmd->opcode == SD_IO_RW_EXTENDED) {
6872c96a293SLudovic Desroches 			cmdr |= ATMCI_CMDR_SDIO_BLOCK;
6882f1d7918SNicolas Ferre 		} else {
6897d2be074SHaavard Skinnemoen 			if (data->flags & MMC_DATA_STREAM)
6902c96a293SLudovic Desroches 				cmdr |= ATMCI_CMDR_STREAM;
6917d2be074SHaavard Skinnemoen 			else if (data->blocks > 1)
6922c96a293SLudovic Desroches 				cmdr |= ATMCI_CMDR_MULTI_BLOCK;
6937d2be074SHaavard Skinnemoen 			else
6942c96a293SLudovic Desroches 				cmdr |= ATMCI_CMDR_BLOCK;
6952f1d7918SNicolas Ferre 		}
6967d2be074SHaavard Skinnemoen 
6977d2be074SHaavard Skinnemoen 		if (data->flags & MMC_DATA_READ)
6982c96a293SLudovic Desroches 			cmdr |= ATMCI_CMDR_TRDIR_READ;
6997d2be074SHaavard Skinnemoen 	}
7007d2be074SHaavard Skinnemoen 
7017d2be074SHaavard Skinnemoen 	return cmdr;
7027d2be074SHaavard Skinnemoen }
7037d2be074SHaavard Skinnemoen 
70411d1488bSLudovic Desroches static void atmci_send_command(struct atmel_mci *host,
705965ebf33SHaavard Skinnemoen 		struct mmc_command *cmd, u32 cmd_flags)
7067d2be074SHaavard Skinnemoen {
7077d2be074SHaavard Skinnemoen 	WARN_ON(host->cmd);
7087d2be074SHaavard Skinnemoen 	host->cmd = cmd;
7097d2be074SHaavard Skinnemoen 
710965ebf33SHaavard Skinnemoen 	dev_vdbg(&host->pdev->dev,
7117d2be074SHaavard Skinnemoen 			"start command: ARGR=0x%08x CMDR=0x%08x\n",
7127d2be074SHaavard Skinnemoen 			cmd->arg, cmd_flags);
7137d2be074SHaavard Skinnemoen 
71403fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_ARGR, cmd->arg);
71503fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_CMDR, cmd_flags);
7167d2be074SHaavard Skinnemoen }
7177d2be074SHaavard Skinnemoen 
7182c96a293SLudovic Desroches static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
7197d2be074SHaavard Skinnemoen {
7206801c41aSLudovic Desroches 	dev_dbg(&host->pdev->dev, "send stop command\n");
72111d1488bSLudovic Desroches 	atmci_send_command(host, data->stop, host->stop_cmdr);
72203fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
7237d2be074SHaavard Skinnemoen }
7247d2be074SHaavard Skinnemoen 
725796211b7SLudovic Desroches /*
726796211b7SLudovic Desroches  * Configure given PDC buffer taking care of alignement issues.
727796211b7SLudovic Desroches  * Update host->data_size and host->sg.
728796211b7SLudovic Desroches  */
729796211b7SLudovic Desroches static void atmci_pdc_set_single_buf(struct atmel_mci *host,
730796211b7SLudovic Desroches 	enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb)
731796211b7SLudovic Desroches {
732796211b7SLudovic Desroches 	u32 pointer_reg, counter_reg;
7337a90dcc2SLudovic Desroches 	unsigned int buf_size;
734796211b7SLudovic Desroches 
735796211b7SLudovic Desroches 	if (dir == XFER_RECEIVE) {
736796211b7SLudovic Desroches 		pointer_reg = ATMEL_PDC_RPR;
737796211b7SLudovic Desroches 		counter_reg = ATMEL_PDC_RCR;
738796211b7SLudovic Desroches 	} else {
739796211b7SLudovic Desroches 		pointer_reg = ATMEL_PDC_TPR;
740796211b7SLudovic Desroches 		counter_reg = ATMEL_PDC_TCR;
741796211b7SLudovic Desroches 	}
742796211b7SLudovic Desroches 
743796211b7SLudovic Desroches 	if (buf_nb == PDC_SECOND_BUF) {
7441ebbe3d3SLudovic Desroches 		pointer_reg += ATMEL_PDC_SCND_BUF_OFF;
7451ebbe3d3SLudovic Desroches 		counter_reg += ATMEL_PDC_SCND_BUF_OFF;
746796211b7SLudovic Desroches 	}
747796211b7SLudovic Desroches 
7487a90dcc2SLudovic Desroches 	if (!host->caps.has_rwproof) {
7497a90dcc2SLudovic Desroches 		buf_size = host->buf_size;
7507a90dcc2SLudovic Desroches 		atmci_writel(host, pointer_reg, host->buf_phys_addr);
7517a90dcc2SLudovic Desroches 	} else {
7527a90dcc2SLudovic Desroches 		buf_size = sg_dma_len(host->sg);
753796211b7SLudovic Desroches 		atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
7547a90dcc2SLudovic Desroches 	}
7557a90dcc2SLudovic Desroches 
7567a90dcc2SLudovic Desroches 	if (host->data_size <= buf_size) {
757796211b7SLudovic Desroches 		if (host->data_size & 0x3) {
758796211b7SLudovic Desroches 			/* If size is different from modulo 4, transfer bytes */
759796211b7SLudovic Desroches 			atmci_writel(host, counter_reg, host->data_size);
760796211b7SLudovic Desroches 			atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE);
761796211b7SLudovic Desroches 		} else {
762796211b7SLudovic Desroches 			/* Else transfer 32-bits words */
763796211b7SLudovic Desroches 			atmci_writel(host, counter_reg, host->data_size / 4);
764796211b7SLudovic Desroches 		}
765796211b7SLudovic Desroches 		host->data_size = 0;
766796211b7SLudovic Desroches 	} else {
767796211b7SLudovic Desroches 		/* We assume the size of a page is 32-bits aligned */
768341fa4c3SLudovic Desroches 		atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4);
769341fa4c3SLudovic Desroches 		host->data_size -= sg_dma_len(host->sg);
770796211b7SLudovic Desroches 		if (host->data_size)
771796211b7SLudovic Desroches 			host->sg = sg_next(host->sg);
772796211b7SLudovic Desroches 	}
773796211b7SLudovic Desroches }
774796211b7SLudovic Desroches 
775796211b7SLudovic Desroches /*
776796211b7SLudovic Desroches  * Configure PDC buffer according to the data size ie configuring one or two
777796211b7SLudovic Desroches  * buffers. Don't use this function if you want to configure only the second
778796211b7SLudovic Desroches  * buffer. In this case, use atmci_pdc_set_single_buf.
779796211b7SLudovic Desroches  */
780796211b7SLudovic Desroches static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir)
781796211b7SLudovic Desroches {
782796211b7SLudovic Desroches 	atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF);
783796211b7SLudovic Desroches 	if (host->data_size)
784796211b7SLudovic Desroches 		atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF);
785796211b7SLudovic Desroches }
786796211b7SLudovic Desroches 
787796211b7SLudovic Desroches /*
788796211b7SLudovic Desroches  * Unmap sg lists, called when transfer is finished.
789796211b7SLudovic Desroches  */
790796211b7SLudovic Desroches static void atmci_pdc_cleanup(struct atmel_mci *host)
791796211b7SLudovic Desroches {
792796211b7SLudovic Desroches 	struct mmc_data         *data = host->data;
793796211b7SLudovic Desroches 
794796211b7SLudovic Desroches 	if (data)
795796211b7SLudovic Desroches 		dma_unmap_sg(&host->pdev->dev,
796796211b7SLudovic Desroches 				data->sg, data->sg_len,
797796211b7SLudovic Desroches 				((data->flags & MMC_DATA_WRITE)
798796211b7SLudovic Desroches 				 ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
799796211b7SLudovic Desroches }
800796211b7SLudovic Desroches 
801796211b7SLudovic Desroches /*
802796211b7SLudovic Desroches  * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after
803796211b7SLudovic Desroches  * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY
804796211b7SLudovic Desroches  * interrupt needed for both transfer directions.
805796211b7SLudovic Desroches  */
806796211b7SLudovic Desroches static void atmci_pdc_complete(struct atmel_mci *host)
807796211b7SLudovic Desroches {
8087a90dcc2SLudovic Desroches 	int transfer_size = host->data->blocks * host->data->blksz;
80924011f34SLudovic Desroches 	int i;
8107a90dcc2SLudovic Desroches 
811796211b7SLudovic Desroches 	atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
8127a90dcc2SLudovic Desroches 
8137a90dcc2SLudovic Desroches 	if ((!host->caps.has_rwproof)
81424011f34SLudovic Desroches 	    && (host->data->flags & MMC_DATA_READ)) {
81524011f34SLudovic Desroches 		if (host->caps.has_bad_data_ordering)
81624011f34SLudovic Desroches 			for (i = 0; i < transfer_size; i++)
81724011f34SLudovic Desroches 				host->buffer[i] = swab32(host->buffer[i]);
8187a90dcc2SLudovic Desroches 		sg_copy_from_buffer(host->data->sg, host->data->sg_len,
8197a90dcc2SLudovic Desroches 		                    host->buffer, transfer_size);
82024011f34SLudovic Desroches 	}
8217a90dcc2SLudovic Desroches 
822796211b7SLudovic Desroches 	atmci_pdc_cleanup(host);
823796211b7SLudovic Desroches 
824796211b7SLudovic Desroches 	/*
825796211b7SLudovic Desroches 	 * If the card was removed, data will be NULL. No point trying
826796211b7SLudovic Desroches 	 * to send the stop command or waiting for NBUSY in this case.
827796211b7SLudovic Desroches 	 */
828796211b7SLudovic Desroches 	if (host->data) {
8296801c41aSLudovic Desroches 		dev_dbg(&host->pdev->dev,
8306801c41aSLudovic Desroches 		        "(%s) set pending xfer complete\n", __func__);
831796211b7SLudovic Desroches 		atmci_set_pending(host, EVENT_XFER_COMPLETE);
832796211b7SLudovic Desroches 		tasklet_schedule(&host->tasklet);
833796211b7SLudovic Desroches 	}
834796211b7SLudovic Desroches }
835796211b7SLudovic Desroches 
83665e8b083SHaavard Skinnemoen static void atmci_dma_cleanup(struct atmel_mci *host)
83765e8b083SHaavard Skinnemoen {
83865e8b083SHaavard Skinnemoen 	struct mmc_data                 *data = host->data;
83965e8b083SHaavard Skinnemoen 
840009a891bSNicolas Ferre 	if (data)
841266ac3f2SLinus Walleij 		dma_unmap_sg(host->dma.chan->device->dev,
842266ac3f2SLinus Walleij 				data->sg, data->sg_len,
84365e8b083SHaavard Skinnemoen 				((data->flags & MMC_DATA_WRITE)
84465e8b083SHaavard Skinnemoen 				 ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
84565e8b083SHaavard Skinnemoen }
84665e8b083SHaavard Skinnemoen 
847796211b7SLudovic Desroches /*
848796211b7SLudovic Desroches  * This function is called by the DMA driver from tasklet context.
849796211b7SLudovic Desroches  */
85065e8b083SHaavard Skinnemoen static void atmci_dma_complete(void *arg)
85165e8b083SHaavard Skinnemoen {
85265e8b083SHaavard Skinnemoen 	struct atmel_mci	*host = arg;
85365e8b083SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
85465e8b083SHaavard Skinnemoen 
85565e8b083SHaavard Skinnemoen 	dev_vdbg(&host->pdev->dev, "DMA complete\n");
85665e8b083SHaavard Skinnemoen 
857ccdfe612SHein_Tibosch 	if (host->caps.has_dma_conf_reg)
85874791a2dSNicolas Ferre 		/* Disable DMA hardware handshaking on MCI */
85903fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
86074791a2dSNicolas Ferre 
86165e8b083SHaavard Skinnemoen 	atmci_dma_cleanup(host);
86265e8b083SHaavard Skinnemoen 
86365e8b083SHaavard Skinnemoen 	/*
86465e8b083SHaavard Skinnemoen 	 * If the card was removed, data will be NULL. No point trying
86565e8b083SHaavard Skinnemoen 	 * to send the stop command or waiting for NBUSY in this case.
86665e8b083SHaavard Skinnemoen 	 */
86765e8b083SHaavard Skinnemoen 	if (data) {
8686801c41aSLudovic Desroches 		dev_dbg(&host->pdev->dev,
8696801c41aSLudovic Desroches 		        "(%s) set pending xfer complete\n", __func__);
87065e8b083SHaavard Skinnemoen 		atmci_set_pending(host, EVENT_XFER_COMPLETE);
87165e8b083SHaavard Skinnemoen 		tasklet_schedule(&host->tasklet);
87265e8b083SHaavard Skinnemoen 
87365e8b083SHaavard Skinnemoen 		/*
87465e8b083SHaavard Skinnemoen 		 * Regardless of what the documentation says, we have
87565e8b083SHaavard Skinnemoen 		 * to wait for NOTBUSY even after block read
87665e8b083SHaavard Skinnemoen 		 * operations.
87765e8b083SHaavard Skinnemoen 		 *
87865e8b083SHaavard Skinnemoen 		 * When the DMA transfer is complete, the controller
87965e8b083SHaavard Skinnemoen 		 * may still be reading the CRC from the card, i.e.
88065e8b083SHaavard Skinnemoen 		 * the data transfer is still in progress and we
88165e8b083SHaavard Skinnemoen 		 * haven't seen all the potential error bits yet.
88265e8b083SHaavard Skinnemoen 		 *
88365e8b083SHaavard Skinnemoen 		 * The interrupt handler will schedule a different
88465e8b083SHaavard Skinnemoen 		 * tasklet to finish things up when the data transfer
88565e8b083SHaavard Skinnemoen 		 * is completely done.
88665e8b083SHaavard Skinnemoen 		 *
88765e8b083SHaavard Skinnemoen 		 * We may not complete the mmc request here anyway
88865e8b083SHaavard Skinnemoen 		 * because the mmc layer may call back and cause us to
88965e8b083SHaavard Skinnemoen 		 * violate the "don't submit new operations from the
89065e8b083SHaavard Skinnemoen 		 * completion callback" rule of the dma engine
89165e8b083SHaavard Skinnemoen 		 * framework.
89265e8b083SHaavard Skinnemoen 		 */
89303fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
89465e8b083SHaavard Skinnemoen 	}
89565e8b083SHaavard Skinnemoen }
89665e8b083SHaavard Skinnemoen 
897796211b7SLudovic Desroches /*
898796211b7SLudovic Desroches  * Returns a mask of interrupt flags to be enabled after the whole
899796211b7SLudovic Desroches  * request has been prepared.
900796211b7SLudovic Desroches  */
901796211b7SLudovic Desroches static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
902796211b7SLudovic Desroches {
903796211b7SLudovic Desroches 	u32 iflags;
904796211b7SLudovic Desroches 
905796211b7SLudovic Desroches 	data->error = -EINPROGRESS;
906796211b7SLudovic Desroches 
907796211b7SLudovic Desroches 	host->sg = data->sg;
908bdbc5d0cSTerry Barnaby 	host->sg_len = data->sg_len;
909796211b7SLudovic Desroches 	host->data = data;
910796211b7SLudovic Desroches 	host->data_chan = NULL;
911796211b7SLudovic Desroches 
912796211b7SLudovic Desroches 	iflags = ATMCI_DATA_ERROR_FLAGS;
913796211b7SLudovic Desroches 
914796211b7SLudovic Desroches 	/*
915796211b7SLudovic Desroches 	 * Errata: MMC data write operation with less than 12
916796211b7SLudovic Desroches 	 * bytes is impossible.
917796211b7SLudovic Desroches 	 *
918796211b7SLudovic Desroches 	 * Errata: MCI Transmit Data Register (TDR) FIFO
919796211b7SLudovic Desroches 	 * corruption when length is not multiple of 4.
920796211b7SLudovic Desroches 	 */
921796211b7SLudovic Desroches 	if (data->blocks * data->blksz < 12
922796211b7SLudovic Desroches 			|| (data->blocks * data->blksz) & 3)
923796211b7SLudovic Desroches 		host->need_reset = true;
924796211b7SLudovic Desroches 
925796211b7SLudovic Desroches 	host->pio_offset = 0;
926796211b7SLudovic Desroches 	if (data->flags & MMC_DATA_READ)
927796211b7SLudovic Desroches 		iflags |= ATMCI_RXRDY;
928796211b7SLudovic Desroches 	else
929796211b7SLudovic Desroches 		iflags |= ATMCI_TXRDY;
930796211b7SLudovic Desroches 
931796211b7SLudovic Desroches 	return iflags;
932796211b7SLudovic Desroches }
933796211b7SLudovic Desroches 
934796211b7SLudovic Desroches /*
935796211b7SLudovic Desroches  * Set interrupt flags and set block length into the MCI mode register even
936796211b7SLudovic Desroches  * if this value is also accessible in the MCI block register. It seems to be
937796211b7SLudovic Desroches  * necessary before the High Speed MCI version. It also map sg and configure
938796211b7SLudovic Desroches  * PDC registers.
939796211b7SLudovic Desroches  */
940796211b7SLudovic Desroches static u32
941796211b7SLudovic Desroches atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
942796211b7SLudovic Desroches {
943796211b7SLudovic Desroches 	u32 iflags, tmp;
944796211b7SLudovic Desroches 	unsigned int sg_len;
945796211b7SLudovic Desroches 	enum dma_data_direction dir;
94624011f34SLudovic Desroches 	int i;
947796211b7SLudovic Desroches 
948796211b7SLudovic Desroches 	data->error = -EINPROGRESS;
949796211b7SLudovic Desroches 
950796211b7SLudovic Desroches 	host->data = data;
951796211b7SLudovic Desroches 	host->sg = data->sg;
952796211b7SLudovic Desroches 	iflags = ATMCI_DATA_ERROR_FLAGS;
953796211b7SLudovic Desroches 
954796211b7SLudovic Desroches 	/* Enable pdc mode */
955796211b7SLudovic Desroches 	atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE);
956796211b7SLudovic Desroches 
957796211b7SLudovic Desroches 	if (data->flags & MMC_DATA_READ) {
958796211b7SLudovic Desroches 		dir = DMA_FROM_DEVICE;
959796211b7SLudovic Desroches 		iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
960796211b7SLudovic Desroches 	} else {
961796211b7SLudovic Desroches 		dir = DMA_TO_DEVICE;
962f5177547SLudovic Desroches 		iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE;
963796211b7SLudovic Desroches 	}
964796211b7SLudovic Desroches 
965796211b7SLudovic Desroches 	/* Set BLKLEN */
966796211b7SLudovic Desroches 	tmp = atmci_readl(host, ATMCI_MR);
967796211b7SLudovic Desroches 	tmp &= 0x0000ffff;
968796211b7SLudovic Desroches 	tmp |= ATMCI_BLKLEN(data->blksz);
969796211b7SLudovic Desroches 	atmci_writel(host, ATMCI_MR, tmp);
970796211b7SLudovic Desroches 
971796211b7SLudovic Desroches 	/* Configure PDC */
972796211b7SLudovic Desroches 	host->data_size = data->blocks * data->blksz;
973796211b7SLudovic Desroches 	sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
9747a90dcc2SLudovic Desroches 
9757a90dcc2SLudovic Desroches 	if ((!host->caps.has_rwproof)
97624011f34SLudovic Desroches 	    && (host->data->flags & MMC_DATA_WRITE)) {
9777a90dcc2SLudovic Desroches 		sg_copy_to_buffer(host->data->sg, host->data->sg_len,
9787a90dcc2SLudovic Desroches 		                  host->buffer, host->data_size);
97924011f34SLudovic Desroches 		if (host->caps.has_bad_data_ordering)
98024011f34SLudovic Desroches 			for (i = 0; i < host->data_size; i++)
98124011f34SLudovic Desroches 				host->buffer[i] = swab32(host->buffer[i]);
98224011f34SLudovic Desroches 	}
9837a90dcc2SLudovic Desroches 
984796211b7SLudovic Desroches 	if (host->data_size)
985796211b7SLudovic Desroches 		atmci_pdc_set_both_buf(host,
986796211b7SLudovic Desroches 			((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
987796211b7SLudovic Desroches 
988796211b7SLudovic Desroches 	return iflags;
989796211b7SLudovic Desroches }
990796211b7SLudovic Desroches 
991796211b7SLudovic Desroches static u32
99274791a2dSNicolas Ferre atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
99365e8b083SHaavard Skinnemoen {
99465e8b083SHaavard Skinnemoen 	struct dma_chan			*chan;
99565e8b083SHaavard Skinnemoen 	struct dma_async_tx_descriptor	*desc;
99665e8b083SHaavard Skinnemoen 	struct scatterlist		*sg;
99765e8b083SHaavard Skinnemoen 	unsigned int			i;
99865e8b083SHaavard Skinnemoen 	enum dma_data_direction		direction;
99905f5799cSVinod Koul 	enum dma_transfer_direction	slave_dirn;
1000657a77faSAtsushi Nemoto 	unsigned int			sglen;
1001693e5e20SNicolas Ferre 	u32				maxburst;
1002796211b7SLudovic Desroches 	u32 iflags;
1003796211b7SLudovic Desroches 
1004796211b7SLudovic Desroches 	data->error = -EINPROGRESS;
1005796211b7SLudovic Desroches 
1006796211b7SLudovic Desroches 	WARN_ON(host->data);
1007796211b7SLudovic Desroches 	host->sg = NULL;
1008796211b7SLudovic Desroches 	host->data = data;
1009796211b7SLudovic Desroches 
1010796211b7SLudovic Desroches 	iflags = ATMCI_DATA_ERROR_FLAGS;
101165e8b083SHaavard Skinnemoen 
101265e8b083SHaavard Skinnemoen 	/*
101365e8b083SHaavard Skinnemoen 	 * We don't do DMA on "complex" transfers, i.e. with
101465e8b083SHaavard Skinnemoen 	 * non-word-aligned buffers or lengths. Also, we don't bother
101565e8b083SHaavard Skinnemoen 	 * with all the DMA setup overhead for short transfers.
101665e8b083SHaavard Skinnemoen 	 */
1017796211b7SLudovic Desroches 	if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
1018796211b7SLudovic Desroches 		return atmci_prepare_data(host, data);
101965e8b083SHaavard Skinnemoen 	if (data->blksz & 3)
1020796211b7SLudovic Desroches 		return atmci_prepare_data(host, data);
102165e8b083SHaavard Skinnemoen 
102265e8b083SHaavard Skinnemoen 	for_each_sg(data->sg, sg, data->sg_len, i) {
102365e8b083SHaavard Skinnemoen 		if (sg->offset & 3 || sg->length & 3)
1024796211b7SLudovic Desroches 			return atmci_prepare_data(host, data);
102565e8b083SHaavard Skinnemoen 	}
102665e8b083SHaavard Skinnemoen 
102765e8b083SHaavard Skinnemoen 	/* If we don't have a channel, we can't do DMA */
102865e8b083SHaavard Skinnemoen 	chan = host->dma.chan;
10296f49a57aSDan Williams 	if (chan)
103065e8b083SHaavard Skinnemoen 		host->data_chan = chan;
103165e8b083SHaavard Skinnemoen 
103265e8b083SHaavard Skinnemoen 	if (!chan)
103365e8b083SHaavard Skinnemoen 		return -ENODEV;
103465e8b083SHaavard Skinnemoen 
103505f5799cSVinod Koul 	if (data->flags & MMC_DATA_READ) {
103665e8b083SHaavard Skinnemoen 		direction = DMA_FROM_DEVICE;
1037e2b35f3dSViresh Kumar 		host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
1038693e5e20SNicolas Ferre 		maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst);
103905f5799cSVinod Koul 	} else {
104065e8b083SHaavard Skinnemoen 		direction = DMA_TO_DEVICE;
1041e2b35f3dSViresh Kumar 		host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
1042693e5e20SNicolas Ferre 		maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
104305f5799cSVinod Koul 	}
104465e8b083SHaavard Skinnemoen 
1045ccdfe612SHein_Tibosch 	if (host->caps.has_dma_conf_reg)
1046ccdfe612SHein_Tibosch 		atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) |
1047ccdfe612SHein_Tibosch 			ATMCI_DMAEN);
1048693e5e20SNicolas Ferre 
1049266ac3f2SLinus Walleij 	sglen = dma_map_sg(chan->device->dev, data->sg,
1050266ac3f2SLinus Walleij 			data->sg_len, direction);
105188ce4db3SLinus Walleij 
1052e2b35f3dSViresh Kumar 	dmaengine_slave_config(chan, &host->dma_conf);
105316052827SAlexandre Bounine 	desc = dmaengine_prep_slave_sg(chan,
105405f5799cSVinod Koul 			data->sg, sglen, slave_dirn,
105565e8b083SHaavard Skinnemoen 			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
105665e8b083SHaavard Skinnemoen 	if (!desc)
1057657a77faSAtsushi Nemoto 		goto unmap_exit;
105865e8b083SHaavard Skinnemoen 
105965e8b083SHaavard Skinnemoen 	host->dma.data_desc = desc;
106065e8b083SHaavard Skinnemoen 	desc->callback = atmci_dma_complete;
106165e8b083SHaavard Skinnemoen 	desc->callback_param = host;
106265e8b083SHaavard Skinnemoen 
1063796211b7SLudovic Desroches 	return iflags;
1064657a77faSAtsushi Nemoto unmap_exit:
106588ce4db3SLinus Walleij 	dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction);
1066657a77faSAtsushi Nemoto 	return -ENOMEM;
106765e8b083SHaavard Skinnemoen }
106865e8b083SHaavard Skinnemoen 
1069796211b7SLudovic Desroches static void
1070796211b7SLudovic Desroches atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
1071796211b7SLudovic Desroches {
1072796211b7SLudovic Desroches 	return;
1073796211b7SLudovic Desroches }
1074796211b7SLudovic Desroches 
1075796211b7SLudovic Desroches /*
1076796211b7SLudovic Desroches  * Start PDC according to transfer direction.
1077796211b7SLudovic Desroches  */
1078796211b7SLudovic Desroches static void
1079796211b7SLudovic Desroches atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data)
1080796211b7SLudovic Desroches {
1081796211b7SLudovic Desroches 	if (data->flags & MMC_DATA_READ)
1082796211b7SLudovic Desroches 		atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
1083796211b7SLudovic Desroches 	else
1084796211b7SLudovic Desroches 		atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
1085796211b7SLudovic Desroches }
1086796211b7SLudovic Desroches 
1087796211b7SLudovic Desroches static void
1088796211b7SLudovic Desroches atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
108974791a2dSNicolas Ferre {
109074791a2dSNicolas Ferre 	struct dma_chan			*chan = host->data_chan;
109174791a2dSNicolas Ferre 	struct dma_async_tx_descriptor	*desc = host->dma.data_desc;
109274791a2dSNicolas Ferre 
109374791a2dSNicolas Ferre 	if (chan) {
10945328906aSLinus Walleij 		dmaengine_submit(desc);
10955328906aSLinus Walleij 		dma_async_issue_pending(chan);
109674791a2dSNicolas Ferre 	}
109774791a2dSNicolas Ferre }
109874791a2dSNicolas Ferre 
1099796211b7SLudovic Desroches static void atmci_stop_transfer(struct atmel_mci *host)
110065e8b083SHaavard Skinnemoen {
11016801c41aSLudovic Desroches 	dev_dbg(&host->pdev->dev,
11026801c41aSLudovic Desroches 	        "(%s) set pending xfer complete\n", __func__);
110365e8b083SHaavard Skinnemoen 	atmci_set_pending(host, EVENT_XFER_COMPLETE);
110403fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
110565e8b083SHaavard Skinnemoen }
110665e8b083SHaavard Skinnemoen 
11077d2be074SHaavard Skinnemoen /*
11087122bbb0SMasanari Iida  * Stop data transfer because error(s) occurred.
11097d2be074SHaavard Skinnemoen  */
1110796211b7SLudovic Desroches static void atmci_stop_transfer_pdc(struct atmel_mci *host)
11117d2be074SHaavard Skinnemoen {
1112f5177547SLudovic Desroches 	atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
1113796211b7SLudovic Desroches }
11147d2be074SHaavard Skinnemoen 
1115796211b7SLudovic Desroches static void atmci_stop_transfer_dma(struct atmel_mci *host)
1116796211b7SLudovic Desroches {
1117796211b7SLudovic Desroches 	struct dma_chan *chan = host->data_chan;
11187d2be074SHaavard Skinnemoen 
1119796211b7SLudovic Desroches 	if (chan) {
1120796211b7SLudovic Desroches 		dmaengine_terminate_all(chan);
1121796211b7SLudovic Desroches 		atmci_dma_cleanup(host);
1122796211b7SLudovic Desroches 	} else {
1123796211b7SLudovic Desroches 		/* Data transfer was stopped by the interrupt handler */
11246801c41aSLudovic Desroches 		dev_dbg(&host->pdev->dev,
11256801c41aSLudovic Desroches 		        "(%s) set pending xfer complete\n", __func__);
1126796211b7SLudovic Desroches 		atmci_set_pending(host, EVENT_XFER_COMPLETE);
1127796211b7SLudovic Desroches 		atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
1128796211b7SLudovic Desroches 	}
1129796211b7SLudovic Desroches }
1130965ebf33SHaavard Skinnemoen 
1131965ebf33SHaavard Skinnemoen /*
1132796211b7SLudovic Desroches  * Start a request: prepare data if needed, prepare the command and activate
1133796211b7SLudovic Desroches  * interrupts.
1134965ebf33SHaavard Skinnemoen  */
1135965ebf33SHaavard Skinnemoen static void atmci_start_request(struct atmel_mci *host,
1136965ebf33SHaavard Skinnemoen 		struct atmel_mci_slot *slot)
11377d2be074SHaavard Skinnemoen {
1138965ebf33SHaavard Skinnemoen 	struct mmc_request	*mrq;
11397d2be074SHaavard Skinnemoen 	struct mmc_command	*cmd;
1140965ebf33SHaavard Skinnemoen 	struct mmc_data		*data;
11417d2be074SHaavard Skinnemoen 	u32			iflags;
1142965ebf33SHaavard Skinnemoen 	u32			cmdflags;
1143965ebf33SHaavard Skinnemoen 
1144965ebf33SHaavard Skinnemoen 	mrq = slot->mrq;
1145965ebf33SHaavard Skinnemoen 	host->cur_slot = slot;
1146965ebf33SHaavard Skinnemoen 	host->mrq = mrq;
1147965ebf33SHaavard Skinnemoen 
1148965ebf33SHaavard Skinnemoen 	host->pending_events = 0;
1149965ebf33SHaavard Skinnemoen 	host->completed_events = 0;
1150f5177547SLudovic Desroches 	host->cmd_status = 0;
1151ca55f46eSHaavard Skinnemoen 	host->data_status = 0;
1152965ebf33SHaavard Skinnemoen 
11536801c41aSLudovic Desroches 	dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode);
11546801c41aSLudovic Desroches 
115524011f34SLudovic Desroches 	if (host->need_reset || host->caps.need_reset_after_xfer) {
115618ee684bSLudovic Desroches 		iflags = atmci_readl(host, ATMCI_IMR);
115718ee684bSLudovic Desroches 		iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
115803fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
115903fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
116003fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_MR, host->mode_reg);
1161796211b7SLudovic Desroches 		if (host->caps.has_cfg_reg)
116203fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_CFG, host->cfg_reg);
116318ee684bSLudovic Desroches 		atmci_writel(host, ATMCI_IER, iflags);
1164965ebf33SHaavard Skinnemoen 		host->need_reset = false;
1165965ebf33SHaavard Skinnemoen 	}
116603fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_SDCR, slot->sdc_reg);
11677d2be074SHaavard Skinnemoen 
116803fc9a7fSLudovic Desroches 	iflags = atmci_readl(host, ATMCI_IMR);
11692c96a293SLudovic Desroches 	if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
1170f5177547SLudovic Desroches 		dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
1171965ebf33SHaavard Skinnemoen 				iflags);
11727d2be074SHaavard Skinnemoen 
1173965ebf33SHaavard Skinnemoen 	if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
1174965ebf33SHaavard Skinnemoen 		/* Send init sequence (74 clock cycles) */
117503fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT);
117603fc9a7fSLudovic Desroches 		while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY))
1177965ebf33SHaavard Skinnemoen 			cpu_relax();
11787d2be074SHaavard Skinnemoen 	}
117974791a2dSNicolas Ferre 	iflags = 0;
11807d2be074SHaavard Skinnemoen 	data = mrq->data;
11817d2be074SHaavard Skinnemoen 	if (data) {
1182965ebf33SHaavard Skinnemoen 		atmci_set_timeout(host, slot, data);
1183a252e3e3SHaavard Skinnemoen 
1184a252e3e3SHaavard Skinnemoen 		/* Must set block count/size before sending command */
118503fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks)
11862c96a293SLudovic Desroches 				| ATMCI_BLKLEN(data->blksz));
1187965ebf33SHaavard Skinnemoen 		dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
11882c96a293SLudovic Desroches 			ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz));
118974791a2dSNicolas Ferre 
1190796211b7SLudovic Desroches 		iflags |= host->prepare_data(host, data);
11917d2be074SHaavard Skinnemoen 	}
11927d2be074SHaavard Skinnemoen 
11932c96a293SLudovic Desroches 	iflags |= ATMCI_CMDRDY;
11947d2be074SHaavard Skinnemoen 	cmd = mrq->cmd;
1195965ebf33SHaavard Skinnemoen 	cmdflags = atmci_prepare_command(slot->mmc, cmd);
119611d1488bSLudovic Desroches 	atmci_send_command(host, cmd, cmdflags);
11977d2be074SHaavard Skinnemoen 
11987d2be074SHaavard Skinnemoen 	if (data)
1199796211b7SLudovic Desroches 		host->submit_data(host, data);
12007d2be074SHaavard Skinnemoen 
12017d2be074SHaavard Skinnemoen 	if (mrq->stop) {
1202965ebf33SHaavard Skinnemoen 		host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
12032c96a293SLudovic Desroches 		host->stop_cmdr |= ATMCI_CMDR_STOP_XFER;
12047d2be074SHaavard Skinnemoen 		if (!(data->flags & MMC_DATA_WRITE))
12052c96a293SLudovic Desroches 			host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ;
12067d2be074SHaavard Skinnemoen 		if (data->flags & MMC_DATA_STREAM)
12072c96a293SLudovic Desroches 			host->stop_cmdr |= ATMCI_CMDR_STREAM;
12087d2be074SHaavard Skinnemoen 		else
12092c96a293SLudovic Desroches 			host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK;
12107d2be074SHaavard Skinnemoen 	}
12117d2be074SHaavard Skinnemoen 
12127d2be074SHaavard Skinnemoen 	/*
12137d2be074SHaavard Skinnemoen 	 * We could have enabled interrupts earlier, but I suspect
12147d2be074SHaavard Skinnemoen 	 * that would open up a nice can of interesting race
12157d2be074SHaavard Skinnemoen 	 * conditions (e.g. command and data complete, but stop not
12167d2be074SHaavard Skinnemoen 	 * prepared yet.)
12177d2be074SHaavard Skinnemoen 	 */
121803fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IER, iflags);
121924011f34SLudovic Desroches 
122024011f34SLudovic Desroches 	mod_timer(&host->timer, jiffies +  msecs_to_jiffies(2000));
1221965ebf33SHaavard Skinnemoen }
12227d2be074SHaavard Skinnemoen 
1223965ebf33SHaavard Skinnemoen static void atmci_queue_request(struct atmel_mci *host,
1224965ebf33SHaavard Skinnemoen 		struct atmel_mci_slot *slot, struct mmc_request *mrq)
1225965ebf33SHaavard Skinnemoen {
1226965ebf33SHaavard Skinnemoen 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
1227965ebf33SHaavard Skinnemoen 			host->state);
1228965ebf33SHaavard Skinnemoen 
1229965ebf33SHaavard Skinnemoen 	spin_lock_bh(&host->lock);
1230965ebf33SHaavard Skinnemoen 	slot->mrq = mrq;
1231965ebf33SHaavard Skinnemoen 	if (host->state == STATE_IDLE) {
1232965ebf33SHaavard Skinnemoen 		host->state = STATE_SENDING_CMD;
1233965ebf33SHaavard Skinnemoen 		atmci_start_request(host, slot);
1234965ebf33SHaavard Skinnemoen 	} else {
12356801c41aSLudovic Desroches 		dev_dbg(&host->pdev->dev, "queue request\n");
1236965ebf33SHaavard Skinnemoen 		list_add_tail(&slot->queue_node, &host->queue);
1237965ebf33SHaavard Skinnemoen 	}
1238965ebf33SHaavard Skinnemoen 	spin_unlock_bh(&host->lock);
1239965ebf33SHaavard Skinnemoen }
1240965ebf33SHaavard Skinnemoen 
1241965ebf33SHaavard Skinnemoen static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1242965ebf33SHaavard Skinnemoen {
1243965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
1244965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = slot->host;
1245965ebf33SHaavard Skinnemoen 	struct mmc_data		*data;
1246965ebf33SHaavard Skinnemoen 
1247965ebf33SHaavard Skinnemoen 	WARN_ON(slot->mrq);
12486801c41aSLudovic Desroches 	dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
1249965ebf33SHaavard Skinnemoen 
1250965ebf33SHaavard Skinnemoen 	/*
1251965ebf33SHaavard Skinnemoen 	 * We may "know" the card is gone even though there's still an
1252965ebf33SHaavard Skinnemoen 	 * electrical connection. If so, we really need to communicate
1253965ebf33SHaavard Skinnemoen 	 * this to the MMC core since there won't be any more
1254965ebf33SHaavard Skinnemoen 	 * interrupts as the card is completely removed. Otherwise,
1255965ebf33SHaavard Skinnemoen 	 * the MMC core might believe the card is still there even
1256965ebf33SHaavard Skinnemoen 	 * though the card was just removed very slowly.
1257965ebf33SHaavard Skinnemoen 	 */
1258965ebf33SHaavard Skinnemoen 	if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
1259965ebf33SHaavard Skinnemoen 		mrq->cmd->error = -ENOMEDIUM;
1260965ebf33SHaavard Skinnemoen 		mmc_request_done(mmc, mrq);
12617d2be074SHaavard Skinnemoen 		return;
1262965ebf33SHaavard Skinnemoen 	}
12637d2be074SHaavard Skinnemoen 
1264965ebf33SHaavard Skinnemoen 	/* We don't support multiple blocks of weird lengths. */
1265965ebf33SHaavard Skinnemoen 	data = mrq->data;
1266965ebf33SHaavard Skinnemoen 	if (data && data->blocks > 1 && data->blksz & 3) {
12677d2be074SHaavard Skinnemoen 		mrq->cmd->error = -EINVAL;
12687d2be074SHaavard Skinnemoen 		mmc_request_done(mmc, mrq);
12697d2be074SHaavard Skinnemoen 	}
12707d2be074SHaavard Skinnemoen 
1271965ebf33SHaavard Skinnemoen 	atmci_queue_request(host, slot, mrq);
1272965ebf33SHaavard Skinnemoen }
1273965ebf33SHaavard Skinnemoen 
12747d2be074SHaavard Skinnemoen static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
12757d2be074SHaavard Skinnemoen {
1276965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
1277965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = slot->host;
1278965ebf33SHaavard Skinnemoen 	unsigned int		i;
1279b3894f26SBoris BREZILLON 	bool			unprepare_clk;
12807d2be074SHaavard Skinnemoen 
12812c96a293SLudovic Desroches 	slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;
1282945533b5SHaavard Skinnemoen 	switch (ios->bus_width) {
1283945533b5SHaavard Skinnemoen 	case MMC_BUS_WIDTH_1:
12842c96a293SLudovic Desroches 		slot->sdc_reg |= ATMCI_SDCBUS_1BIT;
1285945533b5SHaavard Skinnemoen 		break;
1286945533b5SHaavard Skinnemoen 	case MMC_BUS_WIDTH_4:
12872c96a293SLudovic Desroches 		slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
1288945533b5SHaavard Skinnemoen 		break;
1289945533b5SHaavard Skinnemoen 	}
1290945533b5SHaavard Skinnemoen 
12917d2be074SHaavard Skinnemoen 	if (ios->clock) {
1292965ebf33SHaavard Skinnemoen 		unsigned int clock_min = ~0U;
12937d2be074SHaavard Skinnemoen 		u32 clkdiv;
12947d2be074SHaavard Skinnemoen 
1295b3894f26SBoris BREZILLON 		clk_prepare(host->mck);
1296b3894f26SBoris BREZILLON 		unprepare_clk = true;
1297b3894f26SBoris BREZILLON 
1298965ebf33SHaavard Skinnemoen 		spin_lock_bh(&host->lock);
1299965ebf33SHaavard Skinnemoen 		if (!host->mode_reg) {
1300945533b5SHaavard Skinnemoen 			clk_enable(host->mck);
1301b3894f26SBoris BREZILLON 			unprepare_clk = false;
130203fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
130303fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
1304796211b7SLudovic Desroches 			if (host->caps.has_cfg_reg)
130503fc9a7fSLudovic Desroches 				atmci_writel(host, ATMCI_CFG, host->cfg_reg);
1306965ebf33SHaavard Skinnemoen 		}
1307945533b5SHaavard Skinnemoen 
1308965ebf33SHaavard Skinnemoen 		/*
1309965ebf33SHaavard Skinnemoen 		 * Use mirror of ios->clock to prevent race with mmc
1310965ebf33SHaavard Skinnemoen 		 * core ios update when finding the minimum.
1311965ebf33SHaavard Skinnemoen 		 */
1312965ebf33SHaavard Skinnemoen 		slot->clock = ios->clock;
13132c96a293SLudovic Desroches 		for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
1314965ebf33SHaavard Skinnemoen 			if (host->slot[i] && host->slot[i]->clock
1315965ebf33SHaavard Skinnemoen 					&& host->slot[i]->clock < clock_min)
1316965ebf33SHaavard Skinnemoen 				clock_min = host->slot[i]->clock;
1317965ebf33SHaavard Skinnemoen 		}
1318965ebf33SHaavard Skinnemoen 
1319965ebf33SHaavard Skinnemoen 		/* Calculate clock divider */
1320faf8180bSLudovic Desroches 		if (host->caps.has_odd_clk_div) {
1321faf8180bSLudovic Desroches 			clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2;
1322faf8180bSLudovic Desroches 			if (clkdiv > 511) {
1323faf8180bSLudovic Desroches 				dev_warn(&mmc->class_dev,
1324faf8180bSLudovic Desroches 				         "clock %u too slow; using %lu\n",
1325faf8180bSLudovic Desroches 				         clock_min, host->bus_hz / (511 + 2));
1326faf8180bSLudovic Desroches 				clkdiv = 511;
1327faf8180bSLudovic Desroches 			}
1328faf8180bSLudovic Desroches 			host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1)
1329faf8180bSLudovic Desroches 			                 | ATMCI_MR_CLKODD(clkdiv & 1);
1330faf8180bSLudovic Desroches 		} else {
1331965ebf33SHaavard Skinnemoen 			clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
13327d2be074SHaavard Skinnemoen 			if (clkdiv > 255) {
13337d2be074SHaavard Skinnemoen 				dev_warn(&mmc->class_dev,
13347d2be074SHaavard Skinnemoen 				         "clock %u too slow; using %lu\n",
1335965ebf33SHaavard Skinnemoen 				         clock_min, host->bus_hz / (2 * 256));
13367d2be074SHaavard Skinnemoen 				clkdiv = 255;
13377d2be074SHaavard Skinnemoen 			}
13382c96a293SLudovic Desroches 			host->mode_reg = ATMCI_MR_CLKDIV(clkdiv);
1339faf8180bSLudovic Desroches 		}
134004d699c3SRob Emanuele 
1341965ebf33SHaavard Skinnemoen 		/*
1342965ebf33SHaavard Skinnemoen 		 * WRPROOF and RDPROOF prevent overruns/underruns by
1343965ebf33SHaavard Skinnemoen 		 * stopping the clock when the FIFO is full/empty.
1344965ebf33SHaavard Skinnemoen 		 * This state is not expected to last for long.
1345965ebf33SHaavard Skinnemoen 		 */
1346796211b7SLudovic Desroches 		if (host->caps.has_rwproof)
13472c96a293SLudovic Desroches 			host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF);
13487d2be074SHaavard Skinnemoen 
1349796211b7SLudovic Desroches 		if (host->caps.has_cfg_reg) {
135099ddffd8SNicolas Ferre 			/* setup High Speed mode in relation with card capacity */
135199ddffd8SNicolas Ferre 			if (ios->timing == MMC_TIMING_SD_HS)
13522c96a293SLudovic Desroches 				host->cfg_reg |= ATMCI_CFG_HSMODE;
1353965ebf33SHaavard Skinnemoen 			else
13542c96a293SLudovic Desroches 				host->cfg_reg &= ~ATMCI_CFG_HSMODE;
135599ddffd8SNicolas Ferre 		}
135699ddffd8SNicolas Ferre 
135799ddffd8SNicolas Ferre 		if (list_empty(&host->queue)) {
135803fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_MR, host->mode_reg);
1359796211b7SLudovic Desroches 			if (host->caps.has_cfg_reg)
136003fc9a7fSLudovic Desroches 				atmci_writel(host, ATMCI_CFG, host->cfg_reg);
136199ddffd8SNicolas Ferre 		} else {
1362965ebf33SHaavard Skinnemoen 			host->need_clock_update = true;
136399ddffd8SNicolas Ferre 		}
1364965ebf33SHaavard Skinnemoen 
1365965ebf33SHaavard Skinnemoen 		spin_unlock_bh(&host->lock);
1366945533b5SHaavard Skinnemoen 	} else {
1367965ebf33SHaavard Skinnemoen 		bool any_slot_active = false;
1368965ebf33SHaavard Skinnemoen 
1369b3894f26SBoris BREZILLON 		unprepare_clk = false;
1370b3894f26SBoris BREZILLON 
1371965ebf33SHaavard Skinnemoen 		spin_lock_bh(&host->lock);
1372965ebf33SHaavard Skinnemoen 		slot->clock = 0;
13732c96a293SLudovic Desroches 		for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
1374965ebf33SHaavard Skinnemoen 			if (host->slot[i] && host->slot[i]->clock) {
1375965ebf33SHaavard Skinnemoen 				any_slot_active = true;
1376965ebf33SHaavard Skinnemoen 				break;
1377965ebf33SHaavard Skinnemoen 			}
1378965ebf33SHaavard Skinnemoen 		}
1379965ebf33SHaavard Skinnemoen 		if (!any_slot_active) {
138003fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
1381945533b5SHaavard Skinnemoen 			if (host->mode_reg) {
138203fc9a7fSLudovic Desroches 				atmci_readl(host, ATMCI_MR);
1383945533b5SHaavard Skinnemoen 				clk_disable(host->mck);
1384b3894f26SBoris BREZILLON 				unprepare_clk = true;
1385945533b5SHaavard Skinnemoen 			}
1386945533b5SHaavard Skinnemoen 			host->mode_reg = 0;
13877d2be074SHaavard Skinnemoen 		}
1388965ebf33SHaavard Skinnemoen 		spin_unlock_bh(&host->lock);
1389965ebf33SHaavard Skinnemoen 	}
13907d2be074SHaavard Skinnemoen 
1391b3894f26SBoris BREZILLON 	if (unprepare_clk)
1392b3894f26SBoris BREZILLON 		clk_unprepare(host->mck);
1393b3894f26SBoris BREZILLON 
13947d2be074SHaavard Skinnemoen 	switch (ios->power_mode) {
1395965ebf33SHaavard Skinnemoen 	case MMC_POWER_UP:
1396965ebf33SHaavard Skinnemoen 		set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
1397965ebf33SHaavard Skinnemoen 		break;
13987d2be074SHaavard Skinnemoen 	default:
13997d2be074SHaavard Skinnemoen 		/*
14007d2be074SHaavard Skinnemoen 		 * TODO: None of the currently available AVR32-based
14017d2be074SHaavard Skinnemoen 		 * boards allow MMC power to be turned off. Implement
14027d2be074SHaavard Skinnemoen 		 * power control when this can be tested properly.
1403965ebf33SHaavard Skinnemoen 		 *
1404965ebf33SHaavard Skinnemoen 		 * We also need to hook this into the clock management
1405965ebf33SHaavard Skinnemoen 		 * somehow so that newly inserted cards aren't
1406965ebf33SHaavard Skinnemoen 		 * subjected to a fast clock before we have a chance
1407965ebf33SHaavard Skinnemoen 		 * to figure out what the maximum rate is. Currently,
1408965ebf33SHaavard Skinnemoen 		 * there's no way to avoid this, and there never will
1409965ebf33SHaavard Skinnemoen 		 * be for boards that don't support power control.
14107d2be074SHaavard Skinnemoen 		 */
14117d2be074SHaavard Skinnemoen 		break;
14127d2be074SHaavard Skinnemoen 	}
14137d2be074SHaavard Skinnemoen }
14147d2be074SHaavard Skinnemoen 
14157d2be074SHaavard Skinnemoen static int atmci_get_ro(struct mmc_host *mmc)
14167d2be074SHaavard Skinnemoen {
1417965ebf33SHaavard Skinnemoen 	int			read_only = -ENOSYS;
1418965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
14197d2be074SHaavard Skinnemoen 
1420965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->wp_pin)) {
1421965ebf33SHaavard Skinnemoen 		read_only = gpio_get_value(slot->wp_pin);
14227d2be074SHaavard Skinnemoen 		dev_dbg(&mmc->class_dev, "card is %s\n",
14237d2be074SHaavard Skinnemoen 				read_only ? "read-only" : "read-write");
14247d2be074SHaavard Skinnemoen 	}
14257d2be074SHaavard Skinnemoen 
14267d2be074SHaavard Skinnemoen 	return read_only;
14277d2be074SHaavard Skinnemoen }
14287d2be074SHaavard Skinnemoen 
1429965ebf33SHaavard Skinnemoen static int atmci_get_cd(struct mmc_host *mmc)
1430965ebf33SHaavard Skinnemoen {
1431965ebf33SHaavard Skinnemoen 	int			present = -ENOSYS;
1432965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
1433965ebf33SHaavard Skinnemoen 
1434965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
14351c1452beSJonas Larsson 		present = !(gpio_get_value(slot->detect_pin) ^
14361c1452beSJonas Larsson 			    slot->detect_is_active_high);
1437965ebf33SHaavard Skinnemoen 		dev_dbg(&mmc->class_dev, "card is %spresent\n",
1438965ebf33SHaavard Skinnemoen 				present ? "" : "not ");
1439965ebf33SHaavard Skinnemoen 	}
1440965ebf33SHaavard Skinnemoen 
1441965ebf33SHaavard Skinnemoen 	return present;
1442965ebf33SHaavard Skinnemoen }
1443965ebf33SHaavard Skinnemoen 
144488ff82edSAnders Grahn static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
144588ff82edSAnders Grahn {
144688ff82edSAnders Grahn 	struct atmel_mci_slot	*slot = mmc_priv(mmc);
144788ff82edSAnders Grahn 	struct atmel_mci	*host = slot->host;
144888ff82edSAnders Grahn 
144988ff82edSAnders Grahn 	if (enable)
145003fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_IER, slot->sdio_irq);
145188ff82edSAnders Grahn 	else
145203fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_IDR, slot->sdio_irq);
145388ff82edSAnders Grahn }
145488ff82edSAnders Grahn 
1455965ebf33SHaavard Skinnemoen static const struct mmc_host_ops atmci_ops = {
14567d2be074SHaavard Skinnemoen 	.request	= atmci_request,
14577d2be074SHaavard Skinnemoen 	.set_ios	= atmci_set_ios,
14587d2be074SHaavard Skinnemoen 	.get_ro		= atmci_get_ro,
1459965ebf33SHaavard Skinnemoen 	.get_cd		= atmci_get_cd,
146088ff82edSAnders Grahn 	.enable_sdio_irq = atmci_enable_sdio_irq,
14617d2be074SHaavard Skinnemoen };
14627d2be074SHaavard Skinnemoen 
1463965ebf33SHaavard Skinnemoen /* Called with host->lock held */
1464965ebf33SHaavard Skinnemoen static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
1465965ebf33SHaavard Skinnemoen 	__releases(&host->lock)
1466965ebf33SHaavard Skinnemoen 	__acquires(&host->lock)
1467965ebf33SHaavard Skinnemoen {
1468965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = NULL;
1469965ebf33SHaavard Skinnemoen 	struct mmc_host		*prev_mmc = host->cur_slot->mmc;
1470965ebf33SHaavard Skinnemoen 
1471965ebf33SHaavard Skinnemoen 	WARN_ON(host->cmd || host->data);
1472965ebf33SHaavard Skinnemoen 
1473965ebf33SHaavard Skinnemoen 	/*
1474965ebf33SHaavard Skinnemoen 	 * Update the MMC clock rate if necessary. This may be
1475965ebf33SHaavard Skinnemoen 	 * necessary if set_ios() is called when a different slot is
147625985edcSLucas De Marchi 	 * busy transferring data.
1477965ebf33SHaavard Skinnemoen 	 */
147899ddffd8SNicolas Ferre 	if (host->need_clock_update) {
147903fc9a7fSLudovic Desroches 		atmci_writel(host, ATMCI_MR, host->mode_reg);
1480796211b7SLudovic Desroches 		if (host->caps.has_cfg_reg)
148103fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_CFG, host->cfg_reg);
148299ddffd8SNicolas Ferre 	}
1483965ebf33SHaavard Skinnemoen 
1484965ebf33SHaavard Skinnemoen 	host->cur_slot->mrq = NULL;
1485965ebf33SHaavard Skinnemoen 	host->mrq = NULL;
1486965ebf33SHaavard Skinnemoen 	if (!list_empty(&host->queue)) {
1487965ebf33SHaavard Skinnemoen 		slot = list_entry(host->queue.next,
1488965ebf33SHaavard Skinnemoen 				struct atmel_mci_slot, queue_node);
1489965ebf33SHaavard Skinnemoen 		list_del(&slot->queue_node);
1490965ebf33SHaavard Skinnemoen 		dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
1491965ebf33SHaavard Skinnemoen 				mmc_hostname(slot->mmc));
1492965ebf33SHaavard Skinnemoen 		host->state = STATE_SENDING_CMD;
1493965ebf33SHaavard Skinnemoen 		atmci_start_request(host, slot);
1494965ebf33SHaavard Skinnemoen 	} else {
1495965ebf33SHaavard Skinnemoen 		dev_vdbg(&host->pdev->dev, "list empty\n");
1496965ebf33SHaavard Skinnemoen 		host->state = STATE_IDLE;
1497965ebf33SHaavard Skinnemoen 	}
1498965ebf33SHaavard Skinnemoen 
149924011f34SLudovic Desroches 	del_timer(&host->timer);
150024011f34SLudovic Desroches 
1501965ebf33SHaavard Skinnemoen 	spin_unlock(&host->lock);
1502965ebf33SHaavard Skinnemoen 	mmc_request_done(prev_mmc, mrq);
1503965ebf33SHaavard Skinnemoen 	spin_lock(&host->lock);
1504965ebf33SHaavard Skinnemoen }
1505965ebf33SHaavard Skinnemoen 
15067d2be074SHaavard Skinnemoen static void atmci_command_complete(struct atmel_mci *host,
1507c06ad258SHaavard Skinnemoen 			struct mmc_command *cmd)
15087d2be074SHaavard Skinnemoen {
1509c06ad258SHaavard Skinnemoen 	u32		status = host->cmd_status;
1510c06ad258SHaavard Skinnemoen 
15117d2be074SHaavard Skinnemoen 	/* Read the response from the card (up to 16 bytes) */
151203fc9a7fSLudovic Desroches 	cmd->resp[0] = atmci_readl(host, ATMCI_RSPR);
151303fc9a7fSLudovic Desroches 	cmd->resp[1] = atmci_readl(host, ATMCI_RSPR);
151403fc9a7fSLudovic Desroches 	cmd->resp[2] = atmci_readl(host, ATMCI_RSPR);
151503fc9a7fSLudovic Desroches 	cmd->resp[3] = atmci_readl(host, ATMCI_RSPR);
15167d2be074SHaavard Skinnemoen 
15172c96a293SLudovic Desroches 	if (status & ATMCI_RTOE)
15187d2be074SHaavard Skinnemoen 		cmd->error = -ETIMEDOUT;
15192c96a293SLudovic Desroches 	else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE))
15207d2be074SHaavard Skinnemoen 		cmd->error = -EILSEQ;
15212c96a293SLudovic Desroches 	else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE))
15227d2be074SHaavard Skinnemoen 		cmd->error = -EIO;
152324011f34SLudovic Desroches 	else if (host->mrq->data && (host->mrq->data->blksz & 3)) {
152424011f34SLudovic Desroches 		if (host->caps.need_blksz_mul_4) {
152524011f34SLudovic Desroches 			cmd->error = -EINVAL;
152624011f34SLudovic Desroches 			host->need_reset = 1;
152724011f34SLudovic Desroches 		}
152824011f34SLudovic Desroches 	} else
15297d2be074SHaavard Skinnemoen 		cmd->error = 0;
15307d2be074SHaavard Skinnemoen }
15317d2be074SHaavard Skinnemoen 
15327d2be074SHaavard Skinnemoen static void atmci_detect_change(unsigned long data)
15337d2be074SHaavard Skinnemoen {
1534965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = (struct atmel_mci_slot *)data;
1535965ebf33SHaavard Skinnemoen 	bool			present;
1536965ebf33SHaavard Skinnemoen 	bool			present_old;
15377d2be074SHaavard Skinnemoen 
15387d2be074SHaavard Skinnemoen 	/*
1539965ebf33SHaavard Skinnemoen 	 * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
1540965ebf33SHaavard Skinnemoen 	 * freeing the interrupt. We must not re-enable the interrupt
1541965ebf33SHaavard Skinnemoen 	 * if it has been freed, and if we're shutting down, it
1542965ebf33SHaavard Skinnemoen 	 * doesn't really matter whether the card is present or not.
15437d2be074SHaavard Skinnemoen 	 */
15447d2be074SHaavard Skinnemoen 	smp_rmb();
1545965ebf33SHaavard Skinnemoen 	if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
15467d2be074SHaavard Skinnemoen 		return;
15477d2be074SHaavard Skinnemoen 
1548965ebf33SHaavard Skinnemoen 	enable_irq(gpio_to_irq(slot->detect_pin));
15491c1452beSJonas Larsson 	present = !(gpio_get_value(slot->detect_pin) ^
15501c1452beSJonas Larsson 		    slot->detect_is_active_high);
1551965ebf33SHaavard Skinnemoen 	present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
15527d2be074SHaavard Skinnemoen 
1553965ebf33SHaavard Skinnemoen 	dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
1554965ebf33SHaavard Skinnemoen 			present, present_old);
15557d2be074SHaavard Skinnemoen 
1556965ebf33SHaavard Skinnemoen 	if (present != present_old) {
1557965ebf33SHaavard Skinnemoen 		struct atmel_mci	*host = slot->host;
1558965ebf33SHaavard Skinnemoen 		struct mmc_request	*mrq;
1559965ebf33SHaavard Skinnemoen 
1560965ebf33SHaavard Skinnemoen 		dev_dbg(&slot->mmc->class_dev, "card %s\n",
15617d2be074SHaavard Skinnemoen 			present ? "inserted" : "removed");
15627d2be074SHaavard Skinnemoen 
1563965ebf33SHaavard Skinnemoen 		spin_lock(&host->lock);
1564965ebf33SHaavard Skinnemoen 
1565965ebf33SHaavard Skinnemoen 		if (!present)
1566965ebf33SHaavard Skinnemoen 			clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
1567965ebf33SHaavard Skinnemoen 		else
1568965ebf33SHaavard Skinnemoen 			set_bit(ATMCI_CARD_PRESENT, &slot->flags);
15697d2be074SHaavard Skinnemoen 
15707d2be074SHaavard Skinnemoen 		/* Clean up queue if present */
1571965ebf33SHaavard Skinnemoen 		mrq = slot->mrq;
15727d2be074SHaavard Skinnemoen 		if (mrq) {
1573965ebf33SHaavard Skinnemoen 			if (mrq == host->mrq) {
15747d2be074SHaavard Skinnemoen 				/*
15757d2be074SHaavard Skinnemoen 				 * Reset controller to terminate any ongoing
15767d2be074SHaavard Skinnemoen 				 * commands or data transfers.
15777d2be074SHaavard Skinnemoen 				 */
157803fc9a7fSLudovic Desroches 				atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
157903fc9a7fSLudovic Desroches 				atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
158003fc9a7fSLudovic Desroches 				atmci_writel(host, ATMCI_MR, host->mode_reg);
1581796211b7SLudovic Desroches 				if (host->caps.has_cfg_reg)
158203fc9a7fSLudovic Desroches 					atmci_writel(host, ATMCI_CFG, host->cfg_reg);
15837d2be074SHaavard Skinnemoen 
15847d2be074SHaavard Skinnemoen 				host->data = NULL;
15857d2be074SHaavard Skinnemoen 				host->cmd = NULL;
1586c06ad258SHaavard Skinnemoen 
1587c06ad258SHaavard Skinnemoen 				switch (host->state) {
1588965ebf33SHaavard Skinnemoen 				case STATE_IDLE:
1589965ebf33SHaavard Skinnemoen 					break;
1590c06ad258SHaavard Skinnemoen 				case STATE_SENDING_CMD:
1591c06ad258SHaavard Skinnemoen 					mrq->cmd->error = -ENOMEDIUM;
1592f5177547SLudovic Desroches 					if (mrq->data)
1593f5177547SLudovic Desroches 						host->stop_transfer(host);
1594c06ad258SHaavard Skinnemoen 					break;
1595f5177547SLudovic Desroches 				case STATE_DATA_XFER:
1596c06ad258SHaavard Skinnemoen 					mrq->data->error = -ENOMEDIUM;
1597796211b7SLudovic Desroches 					host->stop_transfer(host);
1598c06ad258SHaavard Skinnemoen 					break;
1599f5177547SLudovic Desroches 				case STATE_WAITING_NOTBUSY:
1600c06ad258SHaavard Skinnemoen 					mrq->data->error = -ENOMEDIUM;
1601c06ad258SHaavard Skinnemoen 					break;
1602c06ad258SHaavard Skinnemoen 				case STATE_SENDING_STOP:
1603c06ad258SHaavard Skinnemoen 					mrq->stop->error = -ENOMEDIUM;
1604c06ad258SHaavard Skinnemoen 					break;
1605f5177547SLudovic Desroches 				case STATE_END_REQUEST:
1606f5177547SLudovic Desroches 					break;
1607c06ad258SHaavard Skinnemoen 				}
1608c06ad258SHaavard Skinnemoen 
1609965ebf33SHaavard Skinnemoen 				atmci_request_end(host, mrq);
1610965ebf33SHaavard Skinnemoen 			} else {
1611965ebf33SHaavard Skinnemoen 				list_del(&slot->queue_node);
1612965ebf33SHaavard Skinnemoen 				mrq->cmd->error = -ENOMEDIUM;
1613965ebf33SHaavard Skinnemoen 				if (mrq->data)
1614965ebf33SHaavard Skinnemoen 					mrq->data->error = -ENOMEDIUM;
1615965ebf33SHaavard Skinnemoen 				if (mrq->stop)
1616965ebf33SHaavard Skinnemoen 					mrq->stop->error = -ENOMEDIUM;
16177d2be074SHaavard Skinnemoen 
1618965ebf33SHaavard Skinnemoen 				spin_unlock(&host->lock);
1619965ebf33SHaavard Skinnemoen 				mmc_request_done(slot->mmc, mrq);
1620965ebf33SHaavard Skinnemoen 				spin_lock(&host->lock);
1621965ebf33SHaavard Skinnemoen 			}
1622965ebf33SHaavard Skinnemoen 		}
1623965ebf33SHaavard Skinnemoen 		spin_unlock(&host->lock);
1624965ebf33SHaavard Skinnemoen 
1625965ebf33SHaavard Skinnemoen 		mmc_detect_change(slot->mmc, 0);
16267d2be074SHaavard Skinnemoen 	}
16277d2be074SHaavard Skinnemoen }
16287d2be074SHaavard Skinnemoen 
16297d2be074SHaavard Skinnemoen static void atmci_tasklet_func(unsigned long priv)
16307d2be074SHaavard Skinnemoen {
1631965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = (struct atmel_mci *)priv;
16327d2be074SHaavard Skinnemoen 	struct mmc_request	*mrq = host->mrq;
16337d2be074SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
1634c06ad258SHaavard Skinnemoen 	enum atmel_mci_state	state = host->state;
1635c06ad258SHaavard Skinnemoen 	enum atmel_mci_state	prev_state;
1636c06ad258SHaavard Skinnemoen 	u32			status;
1637c06ad258SHaavard Skinnemoen 
1638965ebf33SHaavard Skinnemoen 	spin_lock(&host->lock);
1639965ebf33SHaavard Skinnemoen 
1640c06ad258SHaavard Skinnemoen 	state = host->state;
16417d2be074SHaavard Skinnemoen 
1642965ebf33SHaavard Skinnemoen 	dev_vdbg(&host->pdev->dev,
1643c06ad258SHaavard Skinnemoen 		"tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
1644c06ad258SHaavard Skinnemoen 		state, host->pending_events, host->completed_events,
164503fc9a7fSLudovic Desroches 		atmci_readl(host, ATMCI_IMR));
16467d2be074SHaavard Skinnemoen 
1647c06ad258SHaavard Skinnemoen 	do {
1648c06ad258SHaavard Skinnemoen 		prev_state = state;
16496801c41aSLudovic Desroches 		dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state);
1650c06ad258SHaavard Skinnemoen 
1651c06ad258SHaavard Skinnemoen 		switch (state) {
1652965ebf33SHaavard Skinnemoen 		case STATE_IDLE:
1653965ebf33SHaavard Skinnemoen 			break;
1654965ebf33SHaavard Skinnemoen 
1655c06ad258SHaavard Skinnemoen 		case STATE_SENDING_CMD:
1656f5177547SLudovic Desroches 			/*
1657f5177547SLudovic Desroches 			 * Command has been sent, we are waiting for command
1658f5177547SLudovic Desroches 			 * ready. Then we have three next states possible:
1659f5177547SLudovic Desroches 			 * END_REQUEST by default, WAITING_NOTBUSY if it's a
1660f5177547SLudovic Desroches 			 * command needing it or DATA_XFER if there is data.
1661f5177547SLudovic Desroches 			 */
16626801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
1663c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1664f5177547SLudovic Desroches 						EVENT_CMD_RDY))
1665c06ad258SHaavard Skinnemoen 				break;
1666c06ad258SHaavard Skinnemoen 
16676801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "set completed cmd ready\n");
16687d2be074SHaavard Skinnemoen 			host->cmd = NULL;
1669f5177547SLudovic Desroches 			atmci_set_completed(host, EVENT_CMD_RDY);
1670c06ad258SHaavard Skinnemoen 			atmci_command_complete(host, mrq->cmd);
1671f5177547SLudovic Desroches 			if (mrq->data) {
16726801c41aSLudovic Desroches 				dev_dbg(&host->pdev->dev,
16736801c41aSLudovic Desroches 				        "command with data transfer");
1674f5177547SLudovic Desroches 				/*
1675f5177547SLudovic Desroches 				 * If there is a command error don't start
1676f5177547SLudovic Desroches 				 * data transfer.
1677f5177547SLudovic Desroches 				 */
1678f5177547SLudovic Desroches 				if (mrq->cmd->error) {
1679f5177547SLudovic Desroches 					host->stop_transfer(host);
1680f5177547SLudovic Desroches 					host->data = NULL;
1681f5177547SLudovic Desroches 					atmci_writel(host, ATMCI_IDR,
1682f5177547SLudovic Desroches 					             ATMCI_TXRDY | ATMCI_RXRDY
1683f5177547SLudovic Desroches 					             | ATMCI_DATA_ERROR_FLAGS);
1684f5177547SLudovic Desroches 					state = STATE_END_REQUEST;
1685f5177547SLudovic Desroches 				} else
1686f5177547SLudovic Desroches 					state = STATE_DATA_XFER;
1687f5177547SLudovic Desroches 			} else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
16886801c41aSLudovic Desroches 				dev_dbg(&host->pdev->dev,
16896801c41aSLudovic Desroches 				        "command response need waiting notbusy");
1690f5177547SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
1691f5177547SLudovic Desroches 				state = STATE_WAITING_NOTBUSY;
1692f5177547SLudovic Desroches 			} else
1693f5177547SLudovic Desroches 				state = STATE_END_REQUEST;
1694c06ad258SHaavard Skinnemoen 
1695f5177547SLudovic Desroches 			break;
1696c06ad258SHaavard Skinnemoen 
1697f5177547SLudovic Desroches 		case STATE_DATA_XFER:
1698c06ad258SHaavard Skinnemoen 			if (atmci_test_and_clear_pending(host,
1699c06ad258SHaavard Skinnemoen 						EVENT_DATA_ERROR)) {
17006801c41aSLudovic Desroches 				dev_dbg(&host->pdev->dev, "set completed data error\n");
1701f5177547SLudovic Desroches 				atmci_set_completed(host, EVENT_DATA_ERROR);
1702f5177547SLudovic Desroches 				state = STATE_END_REQUEST;
1703c06ad258SHaavard Skinnemoen 				break;
17047d2be074SHaavard Skinnemoen 			}
17057d2be074SHaavard Skinnemoen 
1706f5177547SLudovic Desroches 			/*
1707f5177547SLudovic Desroches 			 * A data transfer is in progress. The event expected
1708f5177547SLudovic Desroches 			 * to move to the next state depends of data transfer
1709f5177547SLudovic Desroches 			 * type (PDC or DMA). Once transfer done we can move
1710f5177547SLudovic Desroches 			 * to the next step which is WAITING_NOTBUSY in write
1711f5177547SLudovic Desroches 			 * case and directly SENDING_STOP in read case.
1712f5177547SLudovic Desroches 			 */
17136801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n");
1714c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1715c06ad258SHaavard Skinnemoen 						EVENT_XFER_COMPLETE))
1716c06ad258SHaavard Skinnemoen 				break;
17177d2be074SHaavard Skinnemoen 
17186801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev,
17196801c41aSLudovic Desroches 			        "(%s) set completed xfer complete\n",
17206801c41aSLudovic Desroches 				__func__);
1721c06ad258SHaavard Skinnemoen 			atmci_set_completed(host, EVENT_XFER_COMPLETE);
1722c06ad258SHaavard Skinnemoen 
1723077d4073SLudovic Desroches 			if (host->caps.need_notbusy_for_read_ops ||
1724077d4073SLudovic Desroches 			   (host->data->flags & MMC_DATA_WRITE)) {
1725f5177547SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
1726f5177547SLudovic Desroches 				state = STATE_WAITING_NOTBUSY;
1727f5177547SLudovic Desroches 			} else if (host->mrq->stop) {
1728f5177547SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
1729f5177547SLudovic Desroches 				atmci_send_stop_cmd(host, data);
1730f5177547SLudovic Desroches 				state = STATE_SENDING_STOP;
1731f5177547SLudovic Desroches 			} else {
1732c06ad258SHaavard Skinnemoen 				host->data = NULL;
17337d2be074SHaavard Skinnemoen 				data->bytes_xfered = data->blocks * data->blksz;
17347d2be074SHaavard Skinnemoen 				data->error = 0;
1735f5177547SLudovic Desroches 				state = STATE_END_REQUEST;
17367d2be074SHaavard Skinnemoen 			}
1737f5177547SLudovic Desroches 			break;
17387d2be074SHaavard Skinnemoen 
1739f5177547SLudovic Desroches 		case STATE_WAITING_NOTBUSY:
1740f5177547SLudovic Desroches 			/*
1741f5177547SLudovic Desroches 			 * We can be in the state for two reasons: a command
1742f5177547SLudovic Desroches 			 * requiring waiting not busy signal (stop command
1743f5177547SLudovic Desroches 			 * included) or a write operation. In the latest case,
1744f5177547SLudovic Desroches 			 * we need to send a stop command.
1745f5177547SLudovic Desroches 			 */
17466801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "FSM: not busy?\n");
1747f5177547SLudovic Desroches 			if (!atmci_test_and_clear_pending(host,
1748f5177547SLudovic Desroches 						EVENT_NOTBUSY))
1749f5177547SLudovic Desroches 				break;
17507d2be074SHaavard Skinnemoen 
17516801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "set completed not busy\n");
1752f5177547SLudovic Desroches 			atmci_set_completed(host, EVENT_NOTBUSY);
1753f5177547SLudovic Desroches 
1754f5177547SLudovic Desroches 			if (host->data) {
1755f5177547SLudovic Desroches 				/*
1756f5177547SLudovic Desroches 				 * For some commands such as CMD53, even if
1757f5177547SLudovic Desroches 				 * there is data transfer, there is no stop
1758f5177547SLudovic Desroches 				 * command to send.
1759f5177547SLudovic Desroches 				 */
1760f5177547SLudovic Desroches 				if (host->mrq->stop) {
1761f5177547SLudovic Desroches 					atmci_writel(host, ATMCI_IER,
1762f5177547SLudovic Desroches 					             ATMCI_CMDRDY);
17632c96a293SLudovic Desroches 					atmci_send_stop_cmd(host, data);
1764f5177547SLudovic Desroches 					state = STATE_SENDING_STOP;
1765f5177547SLudovic Desroches 				} else {
1766f5177547SLudovic Desroches 					host->data = NULL;
1767f5177547SLudovic Desroches 					data->bytes_xfered = data->blocks
1768f5177547SLudovic Desroches 					                     * data->blksz;
1769f5177547SLudovic Desroches 					data->error = 0;
1770f5177547SLudovic Desroches 					state = STATE_END_REQUEST;
1771f5177547SLudovic Desroches 				}
1772f5177547SLudovic Desroches 			} else
1773f5177547SLudovic Desroches 				state = STATE_END_REQUEST;
1774f5177547SLudovic Desroches 			break;
1775c06ad258SHaavard Skinnemoen 
1776c06ad258SHaavard Skinnemoen 		case STATE_SENDING_STOP:
1777f5177547SLudovic Desroches 			/*
1778f5177547SLudovic Desroches 			 * In this state, it is important to set host->data to
1779f5177547SLudovic Desroches 			 * NULL (which is tested in the waiting notbusy state)
1780f5177547SLudovic Desroches 			 * in order to go to the end request state instead of
1781f5177547SLudovic Desroches 			 * sending stop again.
1782f5177547SLudovic Desroches 			 */
17836801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
1784c06ad258SHaavard Skinnemoen 			if (!atmci_test_and_clear_pending(host,
1785f5177547SLudovic Desroches 						EVENT_CMD_RDY))
1786c06ad258SHaavard Skinnemoen 				break;
1787c06ad258SHaavard Skinnemoen 
17886801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
1789c06ad258SHaavard Skinnemoen 			host->cmd = NULL;
1790f5177547SLudovic Desroches 			data->bytes_xfered = data->blocks * data->blksz;
1791f5177547SLudovic Desroches 			data->error = 0;
1792c06ad258SHaavard Skinnemoen 			atmci_command_complete(host, mrq->stop);
1793f5177547SLudovic Desroches 			if (mrq->stop->error) {
1794f5177547SLudovic Desroches 				host->stop_transfer(host);
1795f5177547SLudovic Desroches 				atmci_writel(host, ATMCI_IDR,
1796f5177547SLudovic Desroches 				             ATMCI_TXRDY | ATMCI_RXRDY
1797f5177547SLudovic Desroches 				             | ATMCI_DATA_ERROR_FLAGS);
1798f5177547SLudovic Desroches 				state = STATE_END_REQUEST;
1799f5177547SLudovic Desroches 			} else {
1800f5177547SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
1801f5177547SLudovic Desroches 				state = STATE_WAITING_NOTBUSY;
1802f5177547SLudovic Desroches 			}
180341b4e9a1SNicolas Ferre 			host->data = NULL;
1804c06ad258SHaavard Skinnemoen 			break;
1805c06ad258SHaavard Skinnemoen 
1806f5177547SLudovic Desroches 		case STATE_END_REQUEST:
1807f5177547SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY
1808f5177547SLudovic Desroches 			                   | ATMCI_DATA_ERROR_FLAGS);
1809f5177547SLudovic Desroches 			status = host->data_status;
1810f5177547SLudovic Desroches 			if (unlikely(status)) {
1811f5177547SLudovic Desroches 				host->stop_transfer(host);
1812f5177547SLudovic Desroches 				host->data = NULL;
1813fbd986cdSRodolfo Giometti 				if (data) {
1814f5177547SLudovic Desroches 					if (status & ATMCI_DTOE) {
1815f5177547SLudovic Desroches 						data->error = -ETIMEDOUT;
1816f5177547SLudovic Desroches 					} else if (status & ATMCI_DCRCE) {
1817f5177547SLudovic Desroches 						data->error = -EILSEQ;
1818f5177547SLudovic Desroches 					} else {
1819f5177547SLudovic Desroches 						data->error = -EIO;
1820f5177547SLudovic Desroches 					}
1821f5177547SLudovic Desroches 				}
1822fbd986cdSRodolfo Giometti 			}
1823f5177547SLudovic Desroches 
1824f5177547SLudovic Desroches 			atmci_request_end(host, host->mrq);
1825f5177547SLudovic Desroches 			state = STATE_IDLE;
1826c06ad258SHaavard Skinnemoen 			break;
1827c06ad258SHaavard Skinnemoen 		}
1828c06ad258SHaavard Skinnemoen 	} while (state != prev_state);
1829c06ad258SHaavard Skinnemoen 
1830c06ad258SHaavard Skinnemoen 	host->state = state;
1831965ebf33SHaavard Skinnemoen 
1832965ebf33SHaavard Skinnemoen 	spin_unlock(&host->lock);
18337d2be074SHaavard Skinnemoen }
18347d2be074SHaavard Skinnemoen 
18357d2be074SHaavard Skinnemoen static void atmci_read_data_pio(struct atmel_mci *host)
18367d2be074SHaavard Skinnemoen {
18377d2be074SHaavard Skinnemoen 	struct scatterlist	*sg = host->sg;
18387d2be074SHaavard Skinnemoen 	void			*buf = sg_virt(sg);
18397d2be074SHaavard Skinnemoen 	unsigned int		offset = host->pio_offset;
18407d2be074SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
18417d2be074SHaavard Skinnemoen 	u32			value;
18427d2be074SHaavard Skinnemoen 	u32			status;
18437d2be074SHaavard Skinnemoen 	unsigned int		nbytes = 0;
18447d2be074SHaavard Skinnemoen 
18457d2be074SHaavard Skinnemoen 	do {
184603fc9a7fSLudovic Desroches 		value = atmci_readl(host, ATMCI_RDR);
18477d2be074SHaavard Skinnemoen 		if (likely(offset + 4 <= sg->length)) {
18487d2be074SHaavard Skinnemoen 			put_unaligned(value, (u32 *)(buf + offset));
18497d2be074SHaavard Skinnemoen 
18507d2be074SHaavard Skinnemoen 			offset += 4;
18517d2be074SHaavard Skinnemoen 			nbytes += 4;
18527d2be074SHaavard Skinnemoen 
18537d2be074SHaavard Skinnemoen 			if (offset == sg->length) {
18545e7184aeSHaavard Skinnemoen 				flush_dcache_page(sg_page(sg));
18557d2be074SHaavard Skinnemoen 				host->sg = sg = sg_next(sg);
1856bdbc5d0cSTerry Barnaby 				host->sg_len--;
1857bdbc5d0cSTerry Barnaby 				if (!sg || !host->sg_len)
18587d2be074SHaavard Skinnemoen 					goto done;
18597d2be074SHaavard Skinnemoen 
18607d2be074SHaavard Skinnemoen 				offset = 0;
18617d2be074SHaavard Skinnemoen 				buf = sg_virt(sg);
18627d2be074SHaavard Skinnemoen 			}
18637d2be074SHaavard Skinnemoen 		} else {
18647d2be074SHaavard Skinnemoen 			unsigned int remaining = sg->length - offset;
18657d2be074SHaavard Skinnemoen 			memcpy(buf + offset, &value, remaining);
18667d2be074SHaavard Skinnemoen 			nbytes += remaining;
18677d2be074SHaavard Skinnemoen 
18687d2be074SHaavard Skinnemoen 			flush_dcache_page(sg_page(sg));
18697d2be074SHaavard Skinnemoen 			host->sg = sg = sg_next(sg);
1870bdbc5d0cSTerry Barnaby 			host->sg_len--;
1871bdbc5d0cSTerry Barnaby 			if (!sg || !host->sg_len)
18727d2be074SHaavard Skinnemoen 				goto done;
18737d2be074SHaavard Skinnemoen 
18747d2be074SHaavard Skinnemoen 			offset = 4 - remaining;
18757d2be074SHaavard Skinnemoen 			buf = sg_virt(sg);
18767d2be074SHaavard Skinnemoen 			memcpy(buf, (u8 *)&value + remaining, offset);
18777d2be074SHaavard Skinnemoen 			nbytes += offset;
18787d2be074SHaavard Skinnemoen 		}
18797d2be074SHaavard Skinnemoen 
188003fc9a7fSLudovic Desroches 		status = atmci_readl(host, ATMCI_SR);
18817d2be074SHaavard Skinnemoen 		if (status & ATMCI_DATA_ERROR_FLAGS) {
188203fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY
18837d2be074SHaavard Skinnemoen 						| ATMCI_DATA_ERROR_FLAGS));
18847d2be074SHaavard Skinnemoen 			host->data_status = status;
1885965ebf33SHaavard Skinnemoen 			data->bytes_xfered += nbytes;
1886965ebf33SHaavard Skinnemoen 			return;
18877d2be074SHaavard Skinnemoen 		}
18882c96a293SLudovic Desroches 	} while (status & ATMCI_RXRDY);
18897d2be074SHaavard Skinnemoen 
18907d2be074SHaavard Skinnemoen 	host->pio_offset = offset;
18917d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
18927d2be074SHaavard Skinnemoen 
18937d2be074SHaavard Skinnemoen 	return;
18947d2be074SHaavard Skinnemoen 
18957d2be074SHaavard Skinnemoen done:
189603fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY);
189703fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
18987d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
1899965ebf33SHaavard Skinnemoen 	smp_wmb();
1900c06ad258SHaavard Skinnemoen 	atmci_set_pending(host, EVENT_XFER_COMPLETE);
19017d2be074SHaavard Skinnemoen }
19027d2be074SHaavard Skinnemoen 
19037d2be074SHaavard Skinnemoen static void atmci_write_data_pio(struct atmel_mci *host)
19047d2be074SHaavard Skinnemoen {
19057d2be074SHaavard Skinnemoen 	struct scatterlist	*sg = host->sg;
19067d2be074SHaavard Skinnemoen 	void			*buf = sg_virt(sg);
19077d2be074SHaavard Skinnemoen 	unsigned int		offset = host->pio_offset;
19087d2be074SHaavard Skinnemoen 	struct mmc_data		*data = host->data;
19097d2be074SHaavard Skinnemoen 	u32			value;
19107d2be074SHaavard Skinnemoen 	u32			status;
19117d2be074SHaavard Skinnemoen 	unsigned int		nbytes = 0;
19127d2be074SHaavard Skinnemoen 
19137d2be074SHaavard Skinnemoen 	do {
19147d2be074SHaavard Skinnemoen 		if (likely(offset + 4 <= sg->length)) {
19157d2be074SHaavard Skinnemoen 			value = get_unaligned((u32 *)(buf + offset));
191603fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_TDR, value);
19177d2be074SHaavard Skinnemoen 
19187d2be074SHaavard Skinnemoen 			offset += 4;
19197d2be074SHaavard Skinnemoen 			nbytes += 4;
19207d2be074SHaavard Skinnemoen 			if (offset == sg->length) {
19217d2be074SHaavard Skinnemoen 				host->sg = sg = sg_next(sg);
1922bdbc5d0cSTerry Barnaby 				host->sg_len--;
1923bdbc5d0cSTerry Barnaby 				if (!sg || !host->sg_len)
19247d2be074SHaavard Skinnemoen 					goto done;
19257d2be074SHaavard Skinnemoen 
19267d2be074SHaavard Skinnemoen 				offset = 0;
19277d2be074SHaavard Skinnemoen 				buf = sg_virt(sg);
19287d2be074SHaavard Skinnemoen 			}
19297d2be074SHaavard Skinnemoen 		} else {
19307d2be074SHaavard Skinnemoen 			unsigned int remaining = sg->length - offset;
19317d2be074SHaavard Skinnemoen 
19327d2be074SHaavard Skinnemoen 			value = 0;
19337d2be074SHaavard Skinnemoen 			memcpy(&value, buf + offset, remaining);
19347d2be074SHaavard Skinnemoen 			nbytes += remaining;
19357d2be074SHaavard Skinnemoen 
19367d2be074SHaavard Skinnemoen 			host->sg = sg = sg_next(sg);
1937bdbc5d0cSTerry Barnaby 			host->sg_len--;
1938bdbc5d0cSTerry Barnaby 			if (!sg || !host->sg_len) {
193903fc9a7fSLudovic Desroches 				atmci_writel(host, ATMCI_TDR, value);
19407d2be074SHaavard Skinnemoen 				goto done;
19417d2be074SHaavard Skinnemoen 			}
19427d2be074SHaavard Skinnemoen 
19437d2be074SHaavard Skinnemoen 			offset = 4 - remaining;
19447d2be074SHaavard Skinnemoen 			buf = sg_virt(sg);
19457d2be074SHaavard Skinnemoen 			memcpy((u8 *)&value + remaining, buf, offset);
194603fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_TDR, value);
19477d2be074SHaavard Skinnemoen 			nbytes += offset;
19487d2be074SHaavard Skinnemoen 		}
19497d2be074SHaavard Skinnemoen 
195003fc9a7fSLudovic Desroches 		status = atmci_readl(host, ATMCI_SR);
19517d2be074SHaavard Skinnemoen 		if (status & ATMCI_DATA_ERROR_FLAGS) {
195203fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY
19537d2be074SHaavard Skinnemoen 						| ATMCI_DATA_ERROR_FLAGS));
19547d2be074SHaavard Skinnemoen 			host->data_status = status;
1955965ebf33SHaavard Skinnemoen 			data->bytes_xfered += nbytes;
1956965ebf33SHaavard Skinnemoen 			return;
19577d2be074SHaavard Skinnemoen 		}
19582c96a293SLudovic Desroches 	} while (status & ATMCI_TXRDY);
19597d2be074SHaavard Skinnemoen 
19607d2be074SHaavard Skinnemoen 	host->pio_offset = offset;
19617d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
19627d2be074SHaavard Skinnemoen 
19637d2be074SHaavard Skinnemoen 	return;
19647d2be074SHaavard Skinnemoen 
19657d2be074SHaavard Skinnemoen done:
196603fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY);
196703fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
19687d2be074SHaavard Skinnemoen 	data->bytes_xfered += nbytes;
1969965ebf33SHaavard Skinnemoen 	smp_wmb();
1970c06ad258SHaavard Skinnemoen 	atmci_set_pending(host, EVENT_XFER_COMPLETE);
19717d2be074SHaavard Skinnemoen }
19727d2be074SHaavard Skinnemoen 
197388ff82edSAnders Grahn static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
197488ff82edSAnders Grahn {
197588ff82edSAnders Grahn 	int	i;
197688ff82edSAnders Grahn 
19772c96a293SLudovic Desroches 	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
197888ff82edSAnders Grahn 		struct atmel_mci_slot *slot = host->slot[i];
197988ff82edSAnders Grahn 		if (slot && (status & slot->sdio_irq)) {
198088ff82edSAnders Grahn 			mmc_signal_sdio_irq(slot->mmc);
198188ff82edSAnders Grahn 		}
198288ff82edSAnders Grahn 	}
198388ff82edSAnders Grahn }
198488ff82edSAnders Grahn 
198588ff82edSAnders Grahn 
19867d2be074SHaavard Skinnemoen static irqreturn_t atmci_interrupt(int irq, void *dev_id)
19877d2be074SHaavard Skinnemoen {
1988965ebf33SHaavard Skinnemoen 	struct atmel_mci	*host = dev_id;
19897d2be074SHaavard Skinnemoen 	u32			status, mask, pending;
19907d2be074SHaavard Skinnemoen 	unsigned int		pass_count = 0;
19917d2be074SHaavard Skinnemoen 
19927d2be074SHaavard Skinnemoen 	do {
199303fc9a7fSLudovic Desroches 		status = atmci_readl(host, ATMCI_SR);
199403fc9a7fSLudovic Desroches 		mask = atmci_readl(host, ATMCI_IMR);
19957d2be074SHaavard Skinnemoen 		pending = status & mask;
19967d2be074SHaavard Skinnemoen 		if (!pending)
19977d2be074SHaavard Skinnemoen 			break;
19987d2be074SHaavard Skinnemoen 
19997d2be074SHaavard Skinnemoen 		if (pending & ATMCI_DATA_ERROR_FLAGS) {
20006801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: data error\n");
200103fc9a7fSLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
2002f5177547SLudovic Desroches 					| ATMCI_RXRDY | ATMCI_TXRDY
2003f5177547SLudovic Desroches 					| ATMCI_ENDRX | ATMCI_ENDTX
2004f5177547SLudovic Desroches 					| ATMCI_RXBUFF | ATMCI_TXBUFE);
2005965ebf33SHaavard Skinnemoen 
20067d2be074SHaavard Skinnemoen 			host->data_status = status;
20076801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "set pending data error\n");
2008965ebf33SHaavard Skinnemoen 			smp_wmb();
20097d2be074SHaavard Skinnemoen 			atmci_set_pending(host, EVENT_DATA_ERROR);
20107d2be074SHaavard Skinnemoen 			tasklet_schedule(&host->tasklet);
20117d2be074SHaavard Skinnemoen 		}
2012796211b7SLudovic Desroches 
2013796211b7SLudovic Desroches 		if (pending & ATMCI_TXBUFE) {
20146801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n");
2015796211b7SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
20167e8ba228SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
2017796211b7SLudovic Desroches 			/*
2018796211b7SLudovic Desroches 			 * We can receive this interruption before having configured
2019796211b7SLudovic Desroches 			 * the second pdc buffer, so we need to reconfigure first and
2020796211b7SLudovic Desroches 			 * second buffers again
2021796211b7SLudovic Desroches 			 */
2022796211b7SLudovic Desroches 			if (host->data_size) {
2023796211b7SLudovic Desroches 				atmci_pdc_set_both_buf(host, XFER_TRANSMIT);
20247e8ba228SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_ENDTX);
2025796211b7SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE);
2026796211b7SLudovic Desroches 			} else {
2027796211b7SLudovic Desroches 				atmci_pdc_complete(host);
2028796211b7SLudovic Desroches 			}
20297e8ba228SLudovic Desroches 		} else if (pending & ATMCI_ENDTX) {
20306801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n");
20317e8ba228SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
20327e8ba228SLudovic Desroches 
20337e8ba228SLudovic Desroches 			if (host->data_size) {
20347e8ba228SLudovic Desroches 				atmci_pdc_set_single_buf(host,
20357e8ba228SLudovic Desroches 						XFER_TRANSMIT, PDC_SECOND_BUF);
20367e8ba228SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_ENDTX);
20377e8ba228SLudovic Desroches 			}
2038796211b7SLudovic Desroches 		}
2039796211b7SLudovic Desroches 
20407e8ba228SLudovic Desroches 		if (pending & ATMCI_RXBUFF) {
20416801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n");
20427e8ba228SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
20437e8ba228SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
20447e8ba228SLudovic Desroches 			/*
20457e8ba228SLudovic Desroches 			 * We can receive this interruption before having configured
20467e8ba228SLudovic Desroches 			 * the second pdc buffer, so we need to reconfigure first and
20477e8ba228SLudovic Desroches 			 * second buffers again
20487e8ba228SLudovic Desroches 			 */
20497e8ba228SLudovic Desroches 			if (host->data_size) {
20507e8ba228SLudovic Desroches 				atmci_pdc_set_both_buf(host, XFER_RECEIVE);
20517e8ba228SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_ENDRX);
20527e8ba228SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF);
20537e8ba228SLudovic Desroches 			} else {
20547e8ba228SLudovic Desroches 				atmci_pdc_complete(host);
20557e8ba228SLudovic Desroches 			}
20567e8ba228SLudovic Desroches 		} else if (pending & ATMCI_ENDRX) {
20576801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n");
2058796211b7SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
2059796211b7SLudovic Desroches 
2060796211b7SLudovic Desroches 			if (host->data_size) {
2061796211b7SLudovic Desroches 				atmci_pdc_set_single_buf(host,
2062796211b7SLudovic Desroches 						XFER_RECEIVE, PDC_SECOND_BUF);
2063796211b7SLudovic Desroches 				atmci_writel(host, ATMCI_IER, ATMCI_ENDRX);
2064796211b7SLudovic Desroches 			}
2065796211b7SLudovic Desroches 		}
2066796211b7SLudovic Desroches 
2067f5177547SLudovic Desroches 		/*
2068f5177547SLudovic Desroches 		 * First mci IPs, so mainly the ones having pdc, have some
2069f5177547SLudovic Desroches 		 * issues with the notbusy signal. You can't get it after
2070f5177547SLudovic Desroches 		 * data transmission if you have not sent a stop command.
2071f5177547SLudovic Desroches 		 * The appropriate workaround is to use the BLKE signal.
2072f5177547SLudovic Desroches 		 */
2073f5177547SLudovic Desroches 		if (pending & ATMCI_BLKE) {
20746801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: blke\n");
2075f5177547SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
2076965ebf33SHaavard Skinnemoen 			smp_wmb();
20776801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "set pending notbusy\n");
2078f5177547SLudovic Desroches 			atmci_set_pending(host, EVENT_NOTBUSY);
20797d2be074SHaavard Skinnemoen 			tasklet_schedule(&host->tasklet);
20807d2be074SHaavard Skinnemoen 		}
2081f5177547SLudovic Desroches 
2082f5177547SLudovic Desroches 		if (pending & ATMCI_NOTBUSY) {
20836801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: not_busy\n");
2084f5177547SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
2085f5177547SLudovic Desroches 			smp_wmb();
20866801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "set pending notbusy\n");
2087f5177547SLudovic Desroches 			atmci_set_pending(host, EVENT_NOTBUSY);
2088f5177547SLudovic Desroches 			tasklet_schedule(&host->tasklet);
2089f5177547SLudovic Desroches 		}
2090f5177547SLudovic Desroches 
20912c96a293SLudovic Desroches 		if (pending & ATMCI_RXRDY)
20927d2be074SHaavard Skinnemoen 			atmci_read_data_pio(host);
20932c96a293SLudovic Desroches 		if (pending & ATMCI_TXRDY)
20947d2be074SHaavard Skinnemoen 			atmci_write_data_pio(host);
20957d2be074SHaavard Skinnemoen 
2096f5177547SLudovic Desroches 		if (pending & ATMCI_CMDRDY) {
20976801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n");
2098f5177547SLudovic Desroches 			atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
2099f5177547SLudovic Desroches 			host->cmd_status = status;
2100f5177547SLudovic Desroches 			smp_wmb();
21016801c41aSLudovic Desroches 			dev_dbg(&host->pdev->dev, "set pending cmd rdy\n");
2102f5177547SLudovic Desroches 			atmci_set_pending(host, EVENT_CMD_RDY);
2103f5177547SLudovic Desroches 			tasklet_schedule(&host->tasklet);
2104f5177547SLudovic Desroches 		}
210588ff82edSAnders Grahn 
21062c96a293SLudovic Desroches 		if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
210788ff82edSAnders Grahn 			atmci_sdio_interrupt(host, status);
210888ff82edSAnders Grahn 
21097d2be074SHaavard Skinnemoen 	} while (pass_count++ < 5);
21107d2be074SHaavard Skinnemoen 
21117d2be074SHaavard Skinnemoen 	return pass_count ? IRQ_HANDLED : IRQ_NONE;
21127d2be074SHaavard Skinnemoen }
21137d2be074SHaavard Skinnemoen 
21147d2be074SHaavard Skinnemoen static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
21157d2be074SHaavard Skinnemoen {
2116965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot	*slot = dev_id;
21177d2be074SHaavard Skinnemoen 
21187d2be074SHaavard Skinnemoen 	/*
21197d2be074SHaavard Skinnemoen 	 * Disable interrupts until the pin has stabilized and check
21207d2be074SHaavard Skinnemoen 	 * the state then. Use mod_timer() since we may be in the
21217d2be074SHaavard Skinnemoen 	 * middle of the timer routine when this interrupt triggers.
21227d2be074SHaavard Skinnemoen 	 */
21237d2be074SHaavard Skinnemoen 	disable_irq_nosync(irq);
2124965ebf33SHaavard Skinnemoen 	mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
21257d2be074SHaavard Skinnemoen 
21267d2be074SHaavard Skinnemoen 	return IRQ_HANDLED;
21277d2be074SHaavard Skinnemoen }
21287d2be074SHaavard Skinnemoen 
2129965ebf33SHaavard Skinnemoen static int __init atmci_init_slot(struct atmel_mci *host,
2130965ebf33SHaavard Skinnemoen 		struct mci_slot_pdata *slot_data, unsigned int id,
213188ff82edSAnders Grahn 		u32 sdc_reg, u32 sdio_irq)
2132965ebf33SHaavard Skinnemoen {
2133965ebf33SHaavard Skinnemoen 	struct mmc_host			*mmc;
2134965ebf33SHaavard Skinnemoen 	struct atmel_mci_slot		*slot;
2135965ebf33SHaavard Skinnemoen 
2136965ebf33SHaavard Skinnemoen 	mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
2137965ebf33SHaavard Skinnemoen 	if (!mmc)
2138965ebf33SHaavard Skinnemoen 		return -ENOMEM;
2139965ebf33SHaavard Skinnemoen 
2140965ebf33SHaavard Skinnemoen 	slot = mmc_priv(mmc);
2141965ebf33SHaavard Skinnemoen 	slot->mmc = mmc;
2142965ebf33SHaavard Skinnemoen 	slot->host = host;
2143965ebf33SHaavard Skinnemoen 	slot->detect_pin = slot_data->detect_pin;
2144965ebf33SHaavard Skinnemoen 	slot->wp_pin = slot_data->wp_pin;
21451c1452beSJonas Larsson 	slot->detect_is_active_high = slot_data->detect_is_active_high;
2146965ebf33SHaavard Skinnemoen 	slot->sdc_reg = sdc_reg;
214788ff82edSAnders Grahn 	slot->sdio_irq = sdio_irq;
2148965ebf33SHaavard Skinnemoen 
2149e919fd20SLudovic Desroches 	dev_dbg(&mmc->class_dev,
2150e919fd20SLudovic Desroches 	        "slot[%u]: bus_width=%u, detect_pin=%d, "
2151e919fd20SLudovic Desroches 		"detect_is_active_high=%s, wp_pin=%d\n",
2152e919fd20SLudovic Desroches 		id, slot_data->bus_width, slot_data->detect_pin,
2153e919fd20SLudovic Desroches 		slot_data->detect_is_active_high ? "true" : "false",
2154e919fd20SLudovic Desroches 		slot_data->wp_pin);
2155e919fd20SLudovic Desroches 
2156965ebf33SHaavard Skinnemoen 	mmc->ops = &atmci_ops;
2157965ebf33SHaavard Skinnemoen 	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
2158965ebf33SHaavard Skinnemoen 	mmc->f_max = host->bus_hz / 2;
2159965ebf33SHaavard Skinnemoen 	mmc->ocr_avail	= MMC_VDD_32_33 | MMC_VDD_33_34;
216088ff82edSAnders Grahn 	if (sdio_irq)
216188ff82edSAnders Grahn 		mmc->caps |= MMC_CAP_SDIO_IRQ;
2162796211b7SLudovic Desroches 	if (host->caps.has_highspeed)
216399ddffd8SNicolas Ferre 		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
21647a90dcc2SLudovic Desroches 	/*
21657a90dcc2SLudovic Desroches 	 * Without the read/write proof capability, it is strongly suggested to
21667a90dcc2SLudovic Desroches 	 * use only one bit for data to prevent fifo underruns and overruns
21677a90dcc2SLudovic Desroches 	 * which will corrupt data.
21687a90dcc2SLudovic Desroches 	 */
21697a90dcc2SLudovic Desroches 	if ((slot_data->bus_width >= 4) && host->caps.has_rwproof)
2170965ebf33SHaavard Skinnemoen 		mmc->caps |= MMC_CAP_4_BIT_DATA;
2171965ebf33SHaavard Skinnemoen 
21727a90dcc2SLudovic Desroches 	if (atmci_get_version(host) < 0x200) {
21737a90dcc2SLudovic Desroches 		mmc->max_segs = 256;
21747a90dcc2SLudovic Desroches 		mmc->max_blk_size = 4095;
21757a90dcc2SLudovic Desroches 		mmc->max_blk_count = 256;
21767a90dcc2SLudovic Desroches 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
21777a90dcc2SLudovic Desroches 		mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs;
21787a90dcc2SLudovic Desroches 	} else {
2179a36274e0SMartin K. Petersen 		mmc->max_segs = 64;
2180965ebf33SHaavard Skinnemoen 		mmc->max_req_size = 32768 * 512;
2181965ebf33SHaavard Skinnemoen 		mmc->max_blk_size = 32768;
2182965ebf33SHaavard Skinnemoen 		mmc->max_blk_count = 512;
21837a90dcc2SLudovic Desroches 	}
2184965ebf33SHaavard Skinnemoen 
2185965ebf33SHaavard Skinnemoen 	/* Assume card is present initially */
2186965ebf33SHaavard Skinnemoen 	set_bit(ATMCI_CARD_PRESENT, &slot->flags);
2187965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
2188965ebf33SHaavard Skinnemoen 		if (gpio_request(slot->detect_pin, "mmc_detect")) {
2189965ebf33SHaavard Skinnemoen 			dev_dbg(&mmc->class_dev, "no detect pin available\n");
2190965ebf33SHaavard Skinnemoen 			slot->detect_pin = -EBUSY;
21911c1452beSJonas Larsson 		} else if (gpio_get_value(slot->detect_pin) ^
21921c1452beSJonas Larsson 				slot->detect_is_active_high) {
2193965ebf33SHaavard Skinnemoen 			clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
2194965ebf33SHaavard Skinnemoen 		}
2195965ebf33SHaavard Skinnemoen 	}
2196965ebf33SHaavard Skinnemoen 
2197965ebf33SHaavard Skinnemoen 	if (!gpio_is_valid(slot->detect_pin))
2198965ebf33SHaavard Skinnemoen 		mmc->caps |= MMC_CAP_NEEDS_POLL;
2199965ebf33SHaavard Skinnemoen 
2200965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->wp_pin)) {
2201965ebf33SHaavard Skinnemoen 		if (gpio_request(slot->wp_pin, "mmc_wp")) {
2202965ebf33SHaavard Skinnemoen 			dev_dbg(&mmc->class_dev, "no WP pin available\n");
2203965ebf33SHaavard Skinnemoen 			slot->wp_pin = -EBUSY;
2204965ebf33SHaavard Skinnemoen 		}
2205965ebf33SHaavard Skinnemoen 	}
2206965ebf33SHaavard Skinnemoen 
2207965ebf33SHaavard Skinnemoen 	host->slot[id] = slot;
2208965ebf33SHaavard Skinnemoen 	mmc_add_host(mmc);
2209965ebf33SHaavard Skinnemoen 
2210965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
2211965ebf33SHaavard Skinnemoen 		int ret;
2212965ebf33SHaavard Skinnemoen 
2213965ebf33SHaavard Skinnemoen 		setup_timer(&slot->detect_timer, atmci_detect_change,
2214965ebf33SHaavard Skinnemoen 				(unsigned long)slot);
2215965ebf33SHaavard Skinnemoen 
2216965ebf33SHaavard Skinnemoen 		ret = request_irq(gpio_to_irq(slot->detect_pin),
2217965ebf33SHaavard Skinnemoen 				atmci_detect_interrupt,
2218965ebf33SHaavard Skinnemoen 				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
2219965ebf33SHaavard Skinnemoen 				"mmc-detect", slot);
2220965ebf33SHaavard Skinnemoen 		if (ret) {
2221965ebf33SHaavard Skinnemoen 			dev_dbg(&mmc->class_dev,
2222965ebf33SHaavard Skinnemoen 				"could not request IRQ %d for detect pin\n",
2223965ebf33SHaavard Skinnemoen 				gpio_to_irq(slot->detect_pin));
2224965ebf33SHaavard Skinnemoen 			gpio_free(slot->detect_pin);
2225965ebf33SHaavard Skinnemoen 			slot->detect_pin = -EBUSY;
2226965ebf33SHaavard Skinnemoen 		}
2227965ebf33SHaavard Skinnemoen 	}
2228965ebf33SHaavard Skinnemoen 
2229965ebf33SHaavard Skinnemoen 	atmci_init_debugfs(slot);
2230965ebf33SHaavard Skinnemoen 
2231965ebf33SHaavard Skinnemoen 	return 0;
2232965ebf33SHaavard Skinnemoen }
2233965ebf33SHaavard Skinnemoen 
2234965ebf33SHaavard Skinnemoen static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
2235965ebf33SHaavard Skinnemoen 		unsigned int id)
2236965ebf33SHaavard Skinnemoen {
2237965ebf33SHaavard Skinnemoen 	/* Debugfs stuff is cleaned up by mmc core */
2238965ebf33SHaavard Skinnemoen 
2239965ebf33SHaavard Skinnemoen 	set_bit(ATMCI_SHUTDOWN, &slot->flags);
2240965ebf33SHaavard Skinnemoen 	smp_wmb();
2241965ebf33SHaavard Skinnemoen 
2242965ebf33SHaavard Skinnemoen 	mmc_remove_host(slot->mmc);
2243965ebf33SHaavard Skinnemoen 
2244965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->detect_pin)) {
2245965ebf33SHaavard Skinnemoen 		int pin = slot->detect_pin;
2246965ebf33SHaavard Skinnemoen 
2247965ebf33SHaavard Skinnemoen 		free_irq(gpio_to_irq(pin), slot);
2248965ebf33SHaavard Skinnemoen 		del_timer_sync(&slot->detect_timer);
2249965ebf33SHaavard Skinnemoen 		gpio_free(pin);
2250965ebf33SHaavard Skinnemoen 	}
2251965ebf33SHaavard Skinnemoen 	if (gpio_is_valid(slot->wp_pin))
2252965ebf33SHaavard Skinnemoen 		gpio_free(slot->wp_pin);
2253965ebf33SHaavard Skinnemoen 
2254965ebf33SHaavard Skinnemoen 	slot->host->slot[id] = NULL;
2255965ebf33SHaavard Skinnemoen 	mmc_free_host(slot->mmc);
2256965ebf33SHaavard Skinnemoen }
2257965ebf33SHaavard Skinnemoen 
22588c964df0SLudovic Desroches static bool atmci_filter(struct dma_chan *chan, void *pdata)
225974465b4fSDan Williams {
22608c964df0SLudovic Desroches 	struct mci_platform_data *sl_pdata = pdata;
22618c964df0SLudovic Desroches 	struct mci_dma_data *sl;
226274465b4fSDan Williams 
22638c964df0SLudovic Desroches 	if (!sl_pdata)
22648c964df0SLudovic Desroches 		return false;
22658c964df0SLudovic Desroches 
22668c964df0SLudovic Desroches 	sl = sl_pdata->dma_slave;
22672635d1baSNicolas Ferre 	if (sl && find_slave_dev(sl) == chan->device->dev) {
22682635d1baSNicolas Ferre 		chan->private = slave_data_ptr(sl);
22697dd60251SDan Williams 		return true;
22702635d1baSNicolas Ferre 	} else {
22717dd60251SDan Williams 		return false;
227274465b4fSDan Williams 	}
22732635d1baSNicolas Ferre }
22742635d1baSNicolas Ferre 
2275ef878198SLudovic Desroches static bool atmci_configure_dma(struct atmel_mci *host)
22762635d1baSNicolas Ferre {
22772635d1baSNicolas Ferre 	struct mci_platform_data	*pdata;
22788c964df0SLudovic Desroches 	dma_cap_mask_t mask;
22792635d1baSNicolas Ferre 
22802635d1baSNicolas Ferre 	if (host == NULL)
2281ef878198SLudovic Desroches 		return false;
22822635d1baSNicolas Ferre 
22832635d1baSNicolas Ferre 	pdata = host->pdev->dev.platform_data;
22842635d1baSNicolas Ferre 
22852635d1baSNicolas Ferre 	dma_cap_zero(mask);
22862635d1baSNicolas Ferre 	dma_cap_set(DMA_SLAVE, mask);
22878c964df0SLudovic Desroches 
22888c964df0SLudovic Desroches 	host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata,
22898c964df0SLudovic Desroches 							  &host->pdev->dev, "rxtx");
2290ef878198SLudovic Desroches 	if (!host->dma.chan) {
2291ef878198SLudovic Desroches 		dev_warn(&host->pdev->dev, "no DMA channel available\n");
2292ef878198SLudovic Desroches 		return false;
2293ef878198SLudovic Desroches 	} else {
229474791a2dSNicolas Ferre 		dev_info(&host->pdev->dev,
2295b81cfc41SLudovic Desroches 					"using %s for DMA transfers\n",
229674791a2dSNicolas Ferre 					dma_chan_name(host->dma.chan));
2297e2b35f3dSViresh Kumar 
2298e2b35f3dSViresh Kumar 		host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
2299e2b35f3dSViresh Kumar 		host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
2300e2b35f3dSViresh Kumar 		host->dma_conf.src_maxburst = 1;
2301e2b35f3dSViresh Kumar 		host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
2302e2b35f3dSViresh Kumar 		host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
2303e2b35f3dSViresh Kumar 		host->dma_conf.dst_maxburst = 1;
2304e2b35f3dSViresh Kumar 		host->dma_conf.device_fc = false;
2305ef878198SLudovic Desroches 		return true;
2306ef878198SLudovic Desroches 	}
23072635d1baSNicolas Ferre }
2308796211b7SLudovic Desroches 
2309796211b7SLudovic Desroches /*
2310796211b7SLudovic Desroches  * HSMCI (High Speed MCI) module is not fully compatible with MCI module.
2311796211b7SLudovic Desroches  * HSMCI provides DMA support and a new config register but no more supports
2312796211b7SLudovic Desroches  * PDC.
2313796211b7SLudovic Desroches  */
2314796211b7SLudovic Desroches static void __init atmci_get_cap(struct atmel_mci *host)
2315796211b7SLudovic Desroches {
2316796211b7SLudovic Desroches 	unsigned int version;
2317796211b7SLudovic Desroches 
2318796211b7SLudovic Desroches 	version = atmci_get_version(host);
2319796211b7SLudovic Desroches 	dev_info(&host->pdev->dev,
2320796211b7SLudovic Desroches 			"version: 0x%x\n", version);
2321796211b7SLudovic Desroches 
2322ccdfe612SHein_Tibosch 	host->caps.has_dma_conf_reg = 0;
23236bf2af8cSHein_Tibosch 	host->caps.has_pdc = ATMCI_PDC_CONNECTED;
2324796211b7SLudovic Desroches 	host->caps.has_cfg_reg = 0;
2325796211b7SLudovic Desroches 	host->caps.has_cstor_reg = 0;
2326796211b7SLudovic Desroches 	host->caps.has_highspeed = 0;
2327796211b7SLudovic Desroches 	host->caps.has_rwproof = 0;
2328faf8180bSLudovic Desroches 	host->caps.has_odd_clk_div = 0;
232924011f34SLudovic Desroches 	host->caps.has_bad_data_ordering = 1;
233024011f34SLudovic Desroches 	host->caps.need_reset_after_xfer = 1;
233124011f34SLudovic Desroches 	host->caps.need_blksz_mul_4 = 1;
2332077d4073SLudovic Desroches 	host->caps.need_notbusy_for_read_ops = 0;
2333796211b7SLudovic Desroches 
2334796211b7SLudovic Desroches 	/* keep only major version number */
2335796211b7SLudovic Desroches 	switch (version & 0xf00) {
2336796211b7SLudovic Desroches 	case 0x500:
2337faf8180bSLudovic Desroches 		host->caps.has_odd_clk_div = 1;
2338faf8180bSLudovic Desroches 	case 0x400:
2339faf8180bSLudovic Desroches 	case 0x300:
2340ccdfe612SHein_Tibosch 		host->caps.has_dma_conf_reg = 1;
2341faf8180bSLudovic Desroches 		host->caps.has_pdc = 0;
2342796211b7SLudovic Desroches 		host->caps.has_cfg_reg = 1;
2343796211b7SLudovic Desroches 		host->caps.has_cstor_reg = 1;
2344796211b7SLudovic Desroches 		host->caps.has_highspeed = 1;
2345faf8180bSLudovic Desroches 	case 0x200:
2346796211b7SLudovic Desroches 		host->caps.has_rwproof = 1;
234724011f34SLudovic Desroches 		host->caps.need_blksz_mul_4 = 0;
2348077d4073SLudovic Desroches 		host->caps.need_notbusy_for_read_ops = 1;
2349faf8180bSLudovic Desroches 	case 0x100:
235024011f34SLudovic Desroches 		host->caps.has_bad_data_ordering = 0;
235124011f34SLudovic Desroches 		host->caps.need_reset_after_xfer = 0;
235224011f34SLudovic Desroches 	case 0x0:
2353796211b7SLudovic Desroches 		break;
2354796211b7SLudovic Desroches 	default:
2355faf8180bSLudovic Desroches 		host->caps.has_pdc = 0;
2356796211b7SLudovic Desroches 		dev_warn(&host->pdev->dev,
2357796211b7SLudovic Desroches 				"Unmanaged mci version, set minimum capabilities\n");
2358796211b7SLudovic Desroches 		break;
2359796211b7SLudovic Desroches 	}
2360796211b7SLudovic Desroches }
236174465b4fSDan Williams 
23627d2be074SHaavard Skinnemoen static int __init atmci_probe(struct platform_device *pdev)
23637d2be074SHaavard Skinnemoen {
23647d2be074SHaavard Skinnemoen 	struct mci_platform_data	*pdata;
23657d2be074SHaavard Skinnemoen 	struct atmel_mci		*host;
23667d2be074SHaavard Skinnemoen 	struct resource			*regs;
2367965ebf33SHaavard Skinnemoen 	unsigned int			nr_slots;
23687d2be074SHaavard Skinnemoen 	int				irq;
23697d2be074SHaavard Skinnemoen 	int				ret;
23707d2be074SHaavard Skinnemoen 
23717d2be074SHaavard Skinnemoen 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
23727d2be074SHaavard Skinnemoen 	if (!regs)
23737d2be074SHaavard Skinnemoen 		return -ENXIO;
23747d2be074SHaavard Skinnemoen 	pdata = pdev->dev.platform_data;
2375e919fd20SLudovic Desroches 	if (!pdata) {
2376e919fd20SLudovic Desroches 		pdata = atmci_of_init(pdev);
2377e919fd20SLudovic Desroches 		if (IS_ERR(pdata)) {
2378e919fd20SLudovic Desroches 			dev_err(&pdev->dev, "platform data not available\n");
2379e919fd20SLudovic Desroches 			return PTR_ERR(pdata);
2380e919fd20SLudovic Desroches 		}
2381e919fd20SLudovic Desroches 	}
2382e919fd20SLudovic Desroches 
23837d2be074SHaavard Skinnemoen 	irq = platform_get_irq(pdev, 0);
23847d2be074SHaavard Skinnemoen 	if (irq < 0)
23857d2be074SHaavard Skinnemoen 		return irq;
23867d2be074SHaavard Skinnemoen 
2387965ebf33SHaavard Skinnemoen 	host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
2388965ebf33SHaavard Skinnemoen 	if (!host)
23897d2be074SHaavard Skinnemoen 		return -ENOMEM;
23907d2be074SHaavard Skinnemoen 
23917d2be074SHaavard Skinnemoen 	host->pdev = pdev;
2392965ebf33SHaavard Skinnemoen 	spin_lock_init(&host->lock);
2393965ebf33SHaavard Skinnemoen 	INIT_LIST_HEAD(&host->queue);
23947d2be074SHaavard Skinnemoen 
23957d2be074SHaavard Skinnemoen 	host->mck = clk_get(&pdev->dev, "mci_clk");
23967d2be074SHaavard Skinnemoen 	if (IS_ERR(host->mck)) {
23977d2be074SHaavard Skinnemoen 		ret = PTR_ERR(host->mck);
23987d2be074SHaavard Skinnemoen 		goto err_clk_get;
23997d2be074SHaavard Skinnemoen 	}
24007d2be074SHaavard Skinnemoen 
24017d2be074SHaavard Skinnemoen 	ret = -ENOMEM;
2402e8e3f6caSH Hartley Sweeten 	host->regs = ioremap(regs->start, resource_size(regs));
24037d2be074SHaavard Skinnemoen 	if (!host->regs)
24047d2be074SHaavard Skinnemoen 		goto err_ioremap;
24057d2be074SHaavard Skinnemoen 
2406b3894f26SBoris BREZILLON 	ret = clk_prepare_enable(host->mck);
2407b3894f26SBoris BREZILLON 	if (ret)
2408b3894f26SBoris BREZILLON 		goto err_request_irq;
240903fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
24107d2be074SHaavard Skinnemoen 	host->bus_hz = clk_get_rate(host->mck);
2411b3894f26SBoris BREZILLON 	clk_disable_unprepare(host->mck);
24127d2be074SHaavard Skinnemoen 
24137d2be074SHaavard Skinnemoen 	host->mapbase = regs->start;
24147d2be074SHaavard Skinnemoen 
2415965ebf33SHaavard Skinnemoen 	tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
24167d2be074SHaavard Skinnemoen 
241789c8aa20SKay Sievers 	ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
24187d2be074SHaavard Skinnemoen 	if (ret)
24197d2be074SHaavard Skinnemoen 		goto err_request_irq;
24207d2be074SHaavard Skinnemoen 
2421796211b7SLudovic Desroches 	/* Get MCI capabilities and set operations according to it */
2422796211b7SLudovic Desroches 	atmci_get_cap(host);
2423ccdfe612SHein_Tibosch 	if (atmci_configure_dma(host)) {
2424796211b7SLudovic Desroches 		host->prepare_data = &atmci_prepare_data_dma;
2425796211b7SLudovic Desroches 		host->submit_data = &atmci_submit_data_dma;
2426796211b7SLudovic Desroches 		host->stop_transfer = &atmci_stop_transfer_dma;
2427796211b7SLudovic Desroches 	} else if (host->caps.has_pdc) {
2428796211b7SLudovic Desroches 		dev_info(&pdev->dev, "using PDC\n");
2429796211b7SLudovic Desroches 		host->prepare_data = &atmci_prepare_data_pdc;
2430796211b7SLudovic Desroches 		host->submit_data = &atmci_submit_data_pdc;
2431796211b7SLudovic Desroches 		host->stop_transfer = &atmci_stop_transfer_pdc;
2432796211b7SLudovic Desroches 	} else {
2433ef878198SLudovic Desroches 		dev_info(&pdev->dev, "using PIO\n");
2434796211b7SLudovic Desroches 		host->prepare_data = &atmci_prepare_data;
2435796211b7SLudovic Desroches 		host->submit_data = &atmci_submit_data;
2436796211b7SLudovic Desroches 		host->stop_transfer = &atmci_stop_transfer;
2437796211b7SLudovic Desroches 	}
2438796211b7SLudovic Desroches 
24397d2be074SHaavard Skinnemoen 	platform_set_drvdata(pdev, host);
24407d2be074SHaavard Skinnemoen 
2441b87cc1b5SLudovic Desroches 	setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
2442b87cc1b5SLudovic Desroches 
2443965ebf33SHaavard Skinnemoen 	/* We need at least one slot to succeed */
2444965ebf33SHaavard Skinnemoen 	nr_slots = 0;
2445965ebf33SHaavard Skinnemoen 	ret = -ENODEV;
2446965ebf33SHaavard Skinnemoen 	if (pdata->slot[0].bus_width) {
2447965ebf33SHaavard Skinnemoen 		ret = atmci_init_slot(host, &pdata->slot[0],
24482c96a293SLudovic Desroches 				0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
24497a90dcc2SLudovic Desroches 		if (!ret) {
2450965ebf33SHaavard Skinnemoen 			nr_slots++;
24517a90dcc2SLudovic Desroches 			host->buf_size = host->slot[0]->mmc->max_req_size;
24527a90dcc2SLudovic Desroches 		}
24537d2be074SHaavard Skinnemoen 	}
2454965ebf33SHaavard Skinnemoen 	if (pdata->slot[1].bus_width) {
2455965ebf33SHaavard Skinnemoen 		ret = atmci_init_slot(host, &pdata->slot[1],
24562c96a293SLudovic Desroches 				1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
24577a90dcc2SLudovic Desroches 		if (!ret) {
2458965ebf33SHaavard Skinnemoen 			nr_slots++;
24597a90dcc2SLudovic Desroches 			if (host->slot[1]->mmc->max_req_size > host->buf_size)
24607a90dcc2SLudovic Desroches 				host->buf_size =
24617a90dcc2SLudovic Desroches 					host->slot[1]->mmc->max_req_size;
24627a90dcc2SLudovic Desroches 		}
24637d2be074SHaavard Skinnemoen 	}
24647d2be074SHaavard Skinnemoen 
246504d699c3SRob Emanuele 	if (!nr_slots) {
246604d699c3SRob Emanuele 		dev_err(&pdev->dev, "init failed: no slot defined\n");
2467965ebf33SHaavard Skinnemoen 		goto err_init_slot;
246804d699c3SRob Emanuele 	}
24697d2be074SHaavard Skinnemoen 
24707a90dcc2SLudovic Desroches 	if (!host->caps.has_rwproof) {
24717a90dcc2SLudovic Desroches 		host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size,
24727a90dcc2SLudovic Desroches 		                                  &host->buf_phys_addr,
24737a90dcc2SLudovic Desroches 						  GFP_KERNEL);
24747a90dcc2SLudovic Desroches 		if (!host->buffer) {
24757a90dcc2SLudovic Desroches 			ret = -ENOMEM;
24767a90dcc2SLudovic Desroches 			dev_err(&pdev->dev, "buffer allocation failed\n");
24777a90dcc2SLudovic Desroches 			goto err_init_slot;
24787a90dcc2SLudovic Desroches 		}
24797a90dcc2SLudovic Desroches 	}
24807a90dcc2SLudovic Desroches 
2481965ebf33SHaavard Skinnemoen 	dev_info(&pdev->dev,
2482965ebf33SHaavard Skinnemoen 			"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
2483965ebf33SHaavard Skinnemoen 			host->mapbase, irq, nr_slots);
2484deec9ae3SHaavard Skinnemoen 
24857d2be074SHaavard Skinnemoen 	return 0;
24867d2be074SHaavard Skinnemoen 
2487965ebf33SHaavard Skinnemoen err_init_slot:
248874465b4fSDan Williams 	if (host->dma.chan)
248974465b4fSDan Williams 		dma_release_channel(host->dma.chan);
2490965ebf33SHaavard Skinnemoen 	free_irq(irq, host);
24917d2be074SHaavard Skinnemoen err_request_irq:
24927d2be074SHaavard Skinnemoen 	iounmap(host->regs);
24937d2be074SHaavard Skinnemoen err_ioremap:
24947d2be074SHaavard Skinnemoen 	clk_put(host->mck);
24957d2be074SHaavard Skinnemoen err_clk_get:
2496965ebf33SHaavard Skinnemoen 	kfree(host);
24977d2be074SHaavard Skinnemoen 	return ret;
24987d2be074SHaavard Skinnemoen }
24997d2be074SHaavard Skinnemoen 
25007d2be074SHaavard Skinnemoen static int __exit atmci_remove(struct platform_device *pdev)
25017d2be074SHaavard Skinnemoen {
25027d2be074SHaavard Skinnemoen 	struct atmel_mci	*host = platform_get_drvdata(pdev);
2503965ebf33SHaavard Skinnemoen 	unsigned int		i;
25047d2be074SHaavard Skinnemoen 
25057a90dcc2SLudovic Desroches 	if (host->buffer)
25067a90dcc2SLudovic Desroches 		dma_free_coherent(&pdev->dev, host->buf_size,
25077a90dcc2SLudovic Desroches 		                  host->buffer, host->buf_phys_addr);
25087a90dcc2SLudovic Desroches 
25092c96a293SLudovic Desroches 	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
2510965ebf33SHaavard Skinnemoen 		if (host->slot[i])
2511965ebf33SHaavard Skinnemoen 			atmci_cleanup_slot(host->slot[i], i);
25127d2be074SHaavard Skinnemoen 	}
25137d2be074SHaavard Skinnemoen 
2514b3894f26SBoris BREZILLON 	clk_prepare_enable(host->mck);
251503fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_IDR, ~0UL);
251603fc9a7fSLudovic Desroches 	atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
251703fc9a7fSLudovic Desroches 	atmci_readl(host, ATMCI_SR);
2518b3894f26SBoris BREZILLON 	clk_disable_unprepare(host->mck);
25197d2be074SHaavard Skinnemoen 
252074465b4fSDan Williams 	if (host->dma.chan)
252174465b4fSDan Williams 		dma_release_channel(host->dma.chan);
252265e8b083SHaavard Skinnemoen 
2523965ebf33SHaavard Skinnemoen 	free_irq(platform_get_irq(pdev, 0), host);
25247d2be074SHaavard Skinnemoen 	iounmap(host->regs);
25257d2be074SHaavard Skinnemoen 
25267d2be074SHaavard Skinnemoen 	clk_put(host->mck);
2527965ebf33SHaavard Skinnemoen 	kfree(host);
25287d2be074SHaavard Skinnemoen 
25297d2be074SHaavard Skinnemoen 	return 0;
25307d2be074SHaavard Skinnemoen }
25317d2be074SHaavard Skinnemoen 
25325a942b6fSJingoo Han #ifdef CONFIG_PM_SLEEP
25335c2f2b9bSNicolas Ferre static int atmci_suspend(struct device *dev)
25345c2f2b9bSNicolas Ferre {
25355c2f2b9bSNicolas Ferre 	struct atmel_mci *host = dev_get_drvdata(dev);
25365c2f2b9bSNicolas Ferre 	int i;
25375c2f2b9bSNicolas Ferre 
25382c96a293SLudovic Desroches 	 for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
25395c2f2b9bSNicolas Ferre 		struct atmel_mci_slot *slot = host->slot[i];
25405c2f2b9bSNicolas Ferre 		int ret;
25415c2f2b9bSNicolas Ferre 
25425c2f2b9bSNicolas Ferre 		if (!slot)
25435c2f2b9bSNicolas Ferre 			continue;
25445c2f2b9bSNicolas Ferre 		ret = mmc_suspend_host(slot->mmc);
25455c2f2b9bSNicolas Ferre 		if (ret < 0) {
25465c2f2b9bSNicolas Ferre 			while (--i >= 0) {
25475c2f2b9bSNicolas Ferre 				slot = host->slot[i];
25485c2f2b9bSNicolas Ferre 				if (slot
25495c2f2b9bSNicolas Ferre 				&& test_bit(ATMCI_SUSPENDED, &slot->flags)) {
25505c2f2b9bSNicolas Ferre 					mmc_resume_host(host->slot[i]->mmc);
25515c2f2b9bSNicolas Ferre 					clear_bit(ATMCI_SUSPENDED, &slot->flags);
25525c2f2b9bSNicolas Ferre 				}
25535c2f2b9bSNicolas Ferre 			}
25545c2f2b9bSNicolas Ferre 			return ret;
25555c2f2b9bSNicolas Ferre 		} else {
25565c2f2b9bSNicolas Ferre 			set_bit(ATMCI_SUSPENDED, &slot->flags);
25575c2f2b9bSNicolas Ferre 		}
25585c2f2b9bSNicolas Ferre 	}
25595c2f2b9bSNicolas Ferre 
25605c2f2b9bSNicolas Ferre 	return 0;
25615c2f2b9bSNicolas Ferre }
25625c2f2b9bSNicolas Ferre 
25635c2f2b9bSNicolas Ferre static int atmci_resume(struct device *dev)
25645c2f2b9bSNicolas Ferre {
25655c2f2b9bSNicolas Ferre 	struct atmel_mci *host = dev_get_drvdata(dev);
25665c2f2b9bSNicolas Ferre 	int i;
25675c2f2b9bSNicolas Ferre 	int ret = 0;
25685c2f2b9bSNicolas Ferre 
25692c96a293SLudovic Desroches 	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
25705c2f2b9bSNicolas Ferre 		struct atmel_mci_slot *slot = host->slot[i];
25715c2f2b9bSNicolas Ferre 		int err;
25725c2f2b9bSNicolas Ferre 
25735c2f2b9bSNicolas Ferre 		slot = host->slot[i];
25745c2f2b9bSNicolas Ferre 		if (!slot)
25755c2f2b9bSNicolas Ferre 			continue;
25765c2f2b9bSNicolas Ferre 		if (!test_bit(ATMCI_SUSPENDED, &slot->flags))
25775c2f2b9bSNicolas Ferre 			continue;
25785c2f2b9bSNicolas Ferre 		err = mmc_resume_host(slot->mmc);
25795c2f2b9bSNicolas Ferre 		if (err < 0)
25805c2f2b9bSNicolas Ferre 			ret = err;
25815c2f2b9bSNicolas Ferre 		else
25825c2f2b9bSNicolas Ferre 			clear_bit(ATMCI_SUSPENDED, &slot->flags);
25835c2f2b9bSNicolas Ferre 	}
25845c2f2b9bSNicolas Ferre 
25855c2f2b9bSNicolas Ferre 	return ret;
25865c2f2b9bSNicolas Ferre }
25875c2f2b9bSNicolas Ferre #endif
25885c2f2b9bSNicolas Ferre 
25895a942b6fSJingoo Han static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
25905a942b6fSJingoo Han 
25917d2be074SHaavard Skinnemoen static struct platform_driver atmci_driver = {
25927d2be074SHaavard Skinnemoen 	.remove		= __exit_p(atmci_remove),
25937d2be074SHaavard Skinnemoen 	.driver		= {
25947d2be074SHaavard Skinnemoen 		.name		= "atmel_mci",
25955a942b6fSJingoo Han 		.pm		= &atmci_pm,
2596e919fd20SLudovic Desroches 		.of_match_table	= of_match_ptr(atmci_dt_ids),
25977d2be074SHaavard Skinnemoen 	},
25987d2be074SHaavard Skinnemoen };
25997d2be074SHaavard Skinnemoen 
26007d2be074SHaavard Skinnemoen static int __init atmci_init(void)
26017d2be074SHaavard Skinnemoen {
26027d2be074SHaavard Skinnemoen 	return platform_driver_probe(&atmci_driver, atmci_probe);
26037d2be074SHaavard Skinnemoen }
26047d2be074SHaavard Skinnemoen 
26057d2be074SHaavard Skinnemoen static void __exit atmci_exit(void)
26067d2be074SHaavard Skinnemoen {
26077d2be074SHaavard Skinnemoen 	platform_driver_unregister(&atmci_driver);
26087d2be074SHaavard Skinnemoen }
26097d2be074SHaavard Skinnemoen 
261074465b4fSDan Williams late_initcall(atmci_init); /* try to load after dma driver when built-in */
26117d2be074SHaavard Skinnemoen module_exit(atmci_exit);
26127d2be074SHaavard Skinnemoen 
26137d2be074SHaavard Skinnemoen MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
2614e05503efSJean Delvare MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
26157d2be074SHaavard Skinnemoen MODULE_LICENSE("GPL v2");
2616