1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27d2be074SHaavard Skinnemoen /* 37d2be074SHaavard Skinnemoen * Atmel MultiMedia Card Interface driver 47d2be074SHaavard Skinnemoen * 57d2be074SHaavard Skinnemoen * Copyright (C) 2004-2008 Atmel Corporation 67d2be074SHaavard Skinnemoen */ 77d2be074SHaavard Skinnemoen #include <linux/blkdev.h> 87d2be074SHaavard Skinnemoen #include <linux/clk.h> 9deec9ae3SHaavard Skinnemoen #include <linux/debugfs.h> 107d2be074SHaavard Skinnemoen #include <linux/device.h> 1165e8b083SHaavard Skinnemoen #include <linux/dmaengine.h> 1265e8b083SHaavard Skinnemoen #include <linux/dma-mapping.h> 13fbfca4b8SBen Nizette #include <linux/err.h> 143c26e170SDavid Brownell #include <linux/gpio.h> 157d2be074SHaavard Skinnemoen #include <linux/init.h> 167d2be074SHaavard Skinnemoen #include <linux/interrupt.h> 177bca646eSPramod Gurav #include <linux/io.h> 187d2be074SHaavard Skinnemoen #include <linux/ioport.h> 197d2be074SHaavard Skinnemoen #include <linux/module.h> 20e919fd20SLudovic Desroches #include <linux/of.h> 21e919fd20SLudovic Desroches #include <linux/of_device.h> 22e919fd20SLudovic Desroches #include <linux/of_gpio.h> 237d2be074SHaavard Skinnemoen #include <linux/platform_device.h> 247d2be074SHaavard Skinnemoen #include <linux/scatterlist.h> 25deec9ae3SHaavard Skinnemoen #include <linux/seq_file.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 27deec9ae3SHaavard Skinnemoen #include <linux/stat.h> 28e2b35f3dSViresh Kumar #include <linux/types.h> 297d2be074SHaavard Skinnemoen 307d2be074SHaavard Skinnemoen #include <linux/mmc/host.h> 312f1d7918SNicolas Ferre #include <linux/mmc/sdio.h> 322635d1baSNicolas Ferre 33c42aa775SNicolas Ferre #include <linux/atmel-mci.h> 34796211b7SLudovic Desroches #include <linux/atmel_pdc.h> 35ae552ab0SWenyou Yang #include <linux/pm.h> 36ae552ab0SWenyou Yang #include <linux/pm_runtime.h> 37b5b64fa6SWenyou Yang #include <linux/pinctrl/consumer.h> 387d2be074SHaavard Skinnemoen 39bf614c7aSArnd Bergmann #include <asm/cacheflush.h> 407d2be074SHaavard Skinnemoen #include <asm/io.h> 417d2be074SHaavard Skinnemoen #include <asm/unaligned.h> 427d2be074SHaavard Skinnemoen 43ec8fc9cfSludovic.desroches@atmel.com /* 44ef4b160fSAndy Shevchenko * Superset of MCI IP registers integrated in Atmel AT91 Processor 45ec8fc9cfSludovic.desroches@atmel.com * Registers and bitfields marked with [2] are only available in MCI2 46ec8fc9cfSludovic.desroches@atmel.com */ 47ec8fc9cfSludovic.desroches@atmel.com 48ec8fc9cfSludovic.desroches@atmel.com /* MCI Register Definitions */ 49ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR 0x0000 /* Control */ 50ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_MCIEN BIT(0) /* MCI Enable */ 51ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_MCIDIS BIT(1) /* MCI Disable */ 52ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_PWSEN BIT(2) /* Power Save Enable */ 53ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_PWSDIS BIT(3) /* Power Save Disable */ 54ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_SWRST BIT(7) /* Software Reset */ 55ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR 0x0004 /* Mode */ 56ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ 57ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ 58ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_RDPROOF BIT(11) /* Read Proof */ 59ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_WRPROOF BIT(12) /* Write Proof */ 60ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PDCFBYTE BIT(13) /* Force Byte Transfer */ 61ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PDCPADV BIT(14) /* Padding Value */ 62ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PDCMODE BIT(15) /* PDC-oriented Mode */ 63ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ 64ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOR 0x0008 /* Data Timeout */ 65ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ 66ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ 67ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCR 0x000c /* SD Card / SDIO */ 68ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCSEL_SLOT_A (0 << 0) /* Select SD slot A */ 69ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCSEL_SLOT_B (1 << 0) /* Select SD slot A */ 70ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCSEL_MASK (3 << 0) 71ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_1BIT (0 << 6) /* 1-bit data bus */ 72ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_4BIT (2 << 6) /* 4-bit data bus */ 73ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_8BIT (3 << 6) /* 8-bit data bus[2] */ 74ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_MASK (3 << 6) 75ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ARGR 0x0010 /* Command Argument */ 76ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR 0x0014 /* Command */ 77ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ 78ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_RSPTYP_NONE (0 << 6) /* No response */ 79ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_RSPTYP_48BIT (1 << 6) /* 48-bit response */ 80ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_RSPTYP_136BIT (2 << 6) /* 136-bit response */ 81ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_INIT (1 << 8) /* Initialization command */ 82ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_SYNC (2 << 8) /* Synchronized command */ 83ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_INT (4 << 8) /* Interrupt command */ 84ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_INTRESP (5 << 8) /* Interrupt response */ 85ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_OPDCMD (1 << 11) /* Open Drain */ 86ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_MAXLAT_5CYC (0 << 12) /* Max latency 5 cycles */ 87ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_MAXLAT_64CYC (1 << 12) /* Max latency 64 cycles */ 88ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_START_XFER (1 << 16) /* Start data transfer */ 89ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_STOP_XFER (2 << 16) /* Stop data transfer */ 90ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_TRDIR_WRITE (0 << 18) /* Write data */ 91ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_TRDIR_READ (1 << 18) /* Read data */ 92ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_BLOCK (0 << 19) /* Single-block transfer */ 93ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_MULTI_BLOCK (1 << 19) /* Multi-block transfer */ 94ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_STREAM (2 << 19) /* MMC Stream transfer */ 95ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_BYTE (4 << 19) /* SDIO Byte transfer */ 96ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_BLOCK (5 << 19) /* SDIO Block transfer */ 97ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_SUSPEND (1 << 24) /* SDIO Suspend Command */ 98ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_RESUME (2 << 24) /* SDIO Resume Command */ 99ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKR 0x0018 /* Block */ 100ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ 101ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ 102ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ 103ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ 104ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ 105ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR 0x0020 /* Response 0 */ 106ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR1 0x0024 /* Response 1 */ 107ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR2 0x0028 /* Response 2 */ 108ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR3 0x002c /* Response 3 */ 109ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RDR 0x0030 /* Receive Data */ 110ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_TDR 0x0034 /* Transmit Data */ 111ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SR 0x0040 /* Status */ 112ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_IER 0x0044 /* Interrupt Enable */ 113ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_IDR 0x0048 /* Interrupt Disable */ 114ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_IMR 0x004c /* Interrupt Mask */ 115ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDRDY BIT(0) /* Command Ready */ 116ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RXRDY BIT(1) /* Receiver Ready */ 117ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_TXRDY BIT(2) /* Transmitter Ready */ 118ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKE BIT(3) /* Data Block Ended */ 119ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTIP BIT(4) /* Data Transfer In Progress */ 120ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_NOTBUSY BIT(5) /* Data Not Busy */ 121ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ENDRX BIT(6) /* End of RX Buffer */ 122ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ENDTX BIT(7) /* End of TX Buffer */ 123ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDIOIRQA BIT(8) /* SDIO IRQ in slot A */ 124ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDIOIRQB BIT(9) /* SDIO IRQ in slot B */ 125ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDIOWAIT BIT(12) /* SDIO Read Wait Operation Status */ 126ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSRCV BIT(13) /* CE-ATA Completion Signal Received */ 127ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RXBUFF BIT(14) /* RX Buffer Full */ 128ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_TXBUFE BIT(15) /* TX Buffer Empty */ 129ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RINDE BIT(16) /* Response Index Error */ 130ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RDIRE BIT(17) /* Response Direction Error */ 131ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RCRCE BIT(18) /* Response CRC Error */ 132ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RENDE BIT(19) /* Response End Bit Error */ 133ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RTOE BIT(20) /* Response Time-Out Error */ 134ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DCRCE BIT(21) /* Data CRC Error */ 135ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOE BIT(22) /* Data Time-Out Error */ 136ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOE BIT(23) /* Completion Signal Time-out Error */ 137ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKOVRE BIT(24) /* DMA Block Overrun Error */ 138ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMADONE BIT(25) /* DMA Transfer Done */ 139ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_FIFOEMPTY BIT(26) /* FIFO Empty Flag */ 140ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_XFRDONE BIT(27) /* Transfer Done Flag */ 141ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ACKRCV BIT(28) /* Boot Operation Acknowledge Received */ 142ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ACKRCVE BIT(29) /* Boot Operation Acknowledge Error */ 143ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_OVRE BIT(30) /* RX Overrun Error */ 144ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_UNRE BIT(31) /* TX Underrun Error */ 145ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ 146ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ 147ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ 148ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMAEN BIT(8) /* DMA Hardware Handshaking Enable */ 149ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG 0x0054 /* Configuration[2] */ 150ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_FIFOMODE_1DATA BIT(0) /* MCI Internal FIFO control mode */ 151ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_FERRCTRL_COR BIT(4) /* Flow Error flag reset control mode */ 152ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_HSMODE BIT(8) /* High Speed Mode */ 153ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_LSYNC BIT(12) /* Synchronize on the last block */ 154ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ 155ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WP_EN BIT(0) /* WP Enable */ 156ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ 157ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ 158ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_GET_WP_VS(x) ((x) & 0x0f) 159ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) 160ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_VERSION 0x00FC /* Version */ 161ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ 162ec8fc9cfSludovic.desroches@atmel.com 163ec8fc9cfSludovic.desroches@atmel.com /* This is not including the FIFO Aperture on MCI2 */ 164ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_REGS_SIZE 0x100 165ec8fc9cfSludovic.desroches@atmel.com 166ec8fc9cfSludovic.desroches@atmel.com /* Register access macros */ 167ec8fc9cfSludovic.desroches@atmel.com #define atmci_readl(port, reg) \ 168ec8fc9cfSludovic.desroches@atmel.com __raw_readl((port)->regs + reg) 169ec8fc9cfSludovic.desroches@atmel.com #define atmci_writel(port, reg, value) \ 170ec8fc9cfSludovic.desroches@atmel.com __raw_writel((value), (port)->regs + reg) 171ec8fc9cfSludovic.desroches@atmel.com 172ae552ab0SWenyou Yang #define AUTOSUSPEND_DELAY 50 173ae552ab0SWenyou Yang 1742c96a293SLudovic Desroches #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) 17565e8b083SHaavard Skinnemoen #define ATMCI_DMA_THRESHOLD 16 1767d2be074SHaavard Skinnemoen 1777d2be074SHaavard Skinnemoen enum { 178f5177547SLudovic Desroches EVENT_CMD_RDY = 0, 1797d2be074SHaavard Skinnemoen EVENT_XFER_COMPLETE, 180f5177547SLudovic Desroches EVENT_NOTBUSY, 181c06ad258SHaavard Skinnemoen EVENT_DATA_ERROR, 182c06ad258SHaavard Skinnemoen }; 183c06ad258SHaavard Skinnemoen 184c06ad258SHaavard Skinnemoen enum atmel_mci_state { 185965ebf33SHaavard Skinnemoen STATE_IDLE = 0, 186965ebf33SHaavard Skinnemoen STATE_SENDING_CMD, 187f5177547SLudovic Desroches STATE_DATA_XFER, 188f5177547SLudovic Desroches STATE_WAITING_NOTBUSY, 189c06ad258SHaavard Skinnemoen STATE_SENDING_STOP, 190f5177547SLudovic Desroches STATE_END_REQUEST, 1917d2be074SHaavard Skinnemoen }; 1927d2be074SHaavard Skinnemoen 193796211b7SLudovic Desroches enum atmci_xfer_dir { 194796211b7SLudovic Desroches XFER_RECEIVE = 0, 195796211b7SLudovic Desroches XFER_TRANSMIT, 196796211b7SLudovic Desroches }; 197796211b7SLudovic Desroches 198796211b7SLudovic Desroches enum atmci_pdc_buf { 199796211b7SLudovic Desroches PDC_FIRST_BUF = 0, 200796211b7SLudovic Desroches PDC_SECOND_BUF, 201796211b7SLudovic Desroches }; 202796211b7SLudovic Desroches 203796211b7SLudovic Desroches struct atmel_mci_caps { 204ccdfe612SHein_Tibosch bool has_dma_conf_reg; 205796211b7SLudovic Desroches bool has_pdc; 206796211b7SLudovic Desroches bool has_cfg_reg; 207796211b7SLudovic Desroches bool has_cstor_reg; 208796211b7SLudovic Desroches bool has_highspeed; 209796211b7SLudovic Desroches bool has_rwproof; 210faf8180bSLudovic Desroches bool has_odd_clk_div; 21124011f34SLudovic Desroches bool has_bad_data_ordering; 21224011f34SLudovic Desroches bool need_reset_after_xfer; 21324011f34SLudovic Desroches bool need_blksz_mul_4; 214077d4073SLudovic Desroches bool need_notbusy_for_read_ops; 215796211b7SLudovic Desroches }; 216796211b7SLudovic Desroches 21765e8b083SHaavard Skinnemoen struct atmel_mci_dma { 21865e8b083SHaavard Skinnemoen struct dma_chan *chan; 21965e8b083SHaavard Skinnemoen struct dma_async_tx_descriptor *data_desc; 22065e8b083SHaavard Skinnemoen }; 22165e8b083SHaavard Skinnemoen 222965ebf33SHaavard Skinnemoen /** 223965ebf33SHaavard Skinnemoen * struct atmel_mci - MMC controller state shared between all slots 224965ebf33SHaavard Skinnemoen * @lock: Spinlock protecting the queue and associated data. 225965ebf33SHaavard Skinnemoen * @regs: Pointer to MMIO registers. 226796211b7SLudovic Desroches * @sg: Scatterlist entry currently being processed by PIO or PDC code. 227965ebf33SHaavard Skinnemoen * @pio_offset: Offset into the current scatterlist entry. 2287a90dcc2SLudovic Desroches * @buffer: Buffer used if we don't have the r/w proof capability. We 2297a90dcc2SLudovic Desroches * don't have the time to switch pdc buffers so we have to use only 2307a90dcc2SLudovic Desroches * one buffer for the full transaction. 2317a90dcc2SLudovic Desroches * @buf_size: size of the buffer. 2327a90dcc2SLudovic Desroches * @phys_buf_addr: buffer address needed for pdc. 233965ebf33SHaavard Skinnemoen * @cur_slot: The slot which is currently using the controller. 234965ebf33SHaavard Skinnemoen * @mrq: The request currently being processed on @cur_slot, 235965ebf33SHaavard Skinnemoen * or NULL if the controller is idle. 236965ebf33SHaavard Skinnemoen * @cmd: The command currently being sent to the card, or NULL. 237965ebf33SHaavard Skinnemoen * @data: The data currently being transferred, or NULL if no data 238965ebf33SHaavard Skinnemoen * transfer is in progress. 239796211b7SLudovic Desroches * @data_size: just data->blocks * data->blksz. 24065e8b083SHaavard Skinnemoen * @dma: DMA client state. 24165e8b083SHaavard Skinnemoen * @data_chan: DMA channel being used for the current data transfer. 242965ebf33SHaavard Skinnemoen * @cmd_status: Snapshot of SR taken upon completion of the current 243965ebf33SHaavard Skinnemoen * command. Only valid when EVENT_CMD_COMPLETE is pending. 244965ebf33SHaavard Skinnemoen * @data_status: Snapshot of SR taken upon completion of the current 245965ebf33SHaavard Skinnemoen * data transfer. Only valid when EVENT_DATA_COMPLETE or 246965ebf33SHaavard Skinnemoen * EVENT_DATA_ERROR is pending. 247965ebf33SHaavard Skinnemoen * @stop_cmdr: Value to be loaded into CMDR when the stop command is 248965ebf33SHaavard Skinnemoen * to be sent. 249965ebf33SHaavard Skinnemoen * @tasklet: Tasklet running the request state machine. 250965ebf33SHaavard Skinnemoen * @pending_events: Bitmask of events flagged by the interrupt handler 251965ebf33SHaavard Skinnemoen * to be processed by the tasklet. 252965ebf33SHaavard Skinnemoen * @completed_events: Bitmask of events which the state machine has 253965ebf33SHaavard Skinnemoen * processed. 254965ebf33SHaavard Skinnemoen * @state: Tasklet state. 255965ebf33SHaavard Skinnemoen * @queue: List of slots waiting for access to the controller. 256965ebf33SHaavard Skinnemoen * @need_clock_update: Update the clock rate before the next request. 257965ebf33SHaavard Skinnemoen * @need_reset: Reset controller before next request. 25824011f34SLudovic Desroches * @timer: Timer to balance the data timeout error flag which cannot rise. 259965ebf33SHaavard Skinnemoen * @mode_reg: Value of the MR register. 26074791a2dSNicolas Ferre * @cfg_reg: Value of the CFG register. 261965ebf33SHaavard Skinnemoen * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus 262965ebf33SHaavard Skinnemoen * rate and timeout calculations. 263965ebf33SHaavard Skinnemoen * @mapbase: Physical address of the MMIO registers. 264965ebf33SHaavard Skinnemoen * @mck: The peripheral bus clock hooked up to the MMC controller. 265965ebf33SHaavard Skinnemoen * @pdev: Platform device associated with the MMC controller. 266965ebf33SHaavard Skinnemoen * @slot: Slots sharing this MMC controller. 267796211b7SLudovic Desroches * @caps: MCI capabilities depending on MCI version. 268796211b7SLudovic Desroches * @prepare_data: function to setup MCI before data transfer which 269796211b7SLudovic Desroches * depends on MCI capabilities. 270796211b7SLudovic Desroches * @submit_data: function to start data transfer which depends on MCI 271796211b7SLudovic Desroches * capabilities. 272796211b7SLudovic Desroches * @stop_transfer: function to stop data transfer which depends on MCI 273796211b7SLudovic Desroches * capabilities. 274965ebf33SHaavard Skinnemoen * 275965ebf33SHaavard Skinnemoen * Locking 276965ebf33SHaavard Skinnemoen * ======= 277965ebf33SHaavard Skinnemoen * 278965ebf33SHaavard Skinnemoen * @lock is a softirq-safe spinlock protecting @queue as well as 279965ebf33SHaavard Skinnemoen * @cur_slot, @mrq and @state. These must always be updated 280965ebf33SHaavard Skinnemoen * at the same time while holding @lock. 281965ebf33SHaavard Skinnemoen * 282965ebf33SHaavard Skinnemoen * @lock also protects mode_reg and need_clock_update since these are 283965ebf33SHaavard Skinnemoen * used to synchronize mode register updates with the queue 284965ebf33SHaavard Skinnemoen * processing. 285965ebf33SHaavard Skinnemoen * 286965ebf33SHaavard Skinnemoen * The @mrq field of struct atmel_mci_slot is also protected by @lock, 287965ebf33SHaavard Skinnemoen * and must always be written at the same time as the slot is added to 288965ebf33SHaavard Skinnemoen * @queue. 289965ebf33SHaavard Skinnemoen * 290965ebf33SHaavard Skinnemoen * @pending_events and @completed_events are accessed using atomic bit 291965ebf33SHaavard Skinnemoen * operations, so they don't need any locking. 292965ebf33SHaavard Skinnemoen * 293965ebf33SHaavard Skinnemoen * None of the fields touched by the interrupt handler need any 294965ebf33SHaavard Skinnemoen * locking. However, ordering is important: Before EVENT_DATA_ERROR or 295965ebf33SHaavard Skinnemoen * EVENT_DATA_COMPLETE is set in @pending_events, all data-related 296965ebf33SHaavard Skinnemoen * interrupts must be disabled and @data_status updated with a 297965ebf33SHaavard Skinnemoen * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the 29825985edcSLucas De Marchi * CMDRDY interrupt must be disabled and @cmd_status updated with a 299965ebf33SHaavard Skinnemoen * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the 300965ebf33SHaavard Skinnemoen * bytes_xfered field of @data must be written. This is ensured by 301965ebf33SHaavard Skinnemoen * using barriers. 302965ebf33SHaavard Skinnemoen */ 3037d2be074SHaavard Skinnemoen struct atmel_mci { 304965ebf33SHaavard Skinnemoen spinlock_t lock; 3057d2be074SHaavard Skinnemoen void __iomem *regs; 3067d2be074SHaavard Skinnemoen 3077d2be074SHaavard Skinnemoen struct scatterlist *sg; 308bdbc5d0cSTerry Barnaby unsigned int sg_len; 3097d2be074SHaavard Skinnemoen unsigned int pio_offset; 3107a90dcc2SLudovic Desroches unsigned int *buffer; 3117a90dcc2SLudovic Desroches unsigned int buf_size; 3127a90dcc2SLudovic Desroches dma_addr_t buf_phys_addr; 3137d2be074SHaavard Skinnemoen 314965ebf33SHaavard Skinnemoen struct atmel_mci_slot *cur_slot; 3157d2be074SHaavard Skinnemoen struct mmc_request *mrq; 3167d2be074SHaavard Skinnemoen struct mmc_command *cmd; 3177d2be074SHaavard Skinnemoen struct mmc_data *data; 318796211b7SLudovic Desroches unsigned int data_size; 3197d2be074SHaavard Skinnemoen 32065e8b083SHaavard Skinnemoen struct atmel_mci_dma dma; 32165e8b083SHaavard Skinnemoen struct dma_chan *data_chan; 322e2b35f3dSViresh Kumar struct dma_slave_config dma_conf; 32365e8b083SHaavard Skinnemoen 3247d2be074SHaavard Skinnemoen u32 cmd_status; 3257d2be074SHaavard Skinnemoen u32 data_status; 3267d2be074SHaavard Skinnemoen u32 stop_cmdr; 3277d2be074SHaavard Skinnemoen 3287d2be074SHaavard Skinnemoen struct tasklet_struct tasklet; 3297d2be074SHaavard Skinnemoen unsigned long pending_events; 3307d2be074SHaavard Skinnemoen unsigned long completed_events; 331c06ad258SHaavard Skinnemoen enum atmel_mci_state state; 332965ebf33SHaavard Skinnemoen struct list_head queue; 3337d2be074SHaavard Skinnemoen 334965ebf33SHaavard Skinnemoen bool need_clock_update; 335965ebf33SHaavard Skinnemoen bool need_reset; 33624011f34SLudovic Desroches struct timer_list timer; 337965ebf33SHaavard Skinnemoen u32 mode_reg; 33874791a2dSNicolas Ferre u32 cfg_reg; 3397d2be074SHaavard Skinnemoen unsigned long bus_hz; 3407d2be074SHaavard Skinnemoen unsigned long mapbase; 3417d2be074SHaavard Skinnemoen struct clk *mck; 3427d2be074SHaavard Skinnemoen struct platform_device *pdev; 343965ebf33SHaavard Skinnemoen 3442c96a293SLudovic Desroches struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS]; 345796211b7SLudovic Desroches 346796211b7SLudovic Desroches struct atmel_mci_caps caps; 347796211b7SLudovic Desroches 348796211b7SLudovic Desroches u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data); 349796211b7SLudovic Desroches void (*submit_data)(struct atmel_mci *host, struct mmc_data *data); 350796211b7SLudovic Desroches void (*stop_transfer)(struct atmel_mci *host); 351965ebf33SHaavard Skinnemoen }; 352965ebf33SHaavard Skinnemoen 353965ebf33SHaavard Skinnemoen /** 354965ebf33SHaavard Skinnemoen * struct atmel_mci_slot - MMC slot state 355965ebf33SHaavard Skinnemoen * @mmc: The mmc_host representing this slot. 356965ebf33SHaavard Skinnemoen * @host: The MMC controller this slot is using. 357965ebf33SHaavard Skinnemoen * @sdc_reg: Value of SDCR to be written before using this slot. 35888ff82edSAnders Grahn * @sdio_irq: SDIO irq mask for this slot. 359965ebf33SHaavard Skinnemoen * @mrq: mmc_request currently being processed or waiting to be 360965ebf33SHaavard Skinnemoen * processed, or NULL when the slot is idle. 361965ebf33SHaavard Skinnemoen * @queue_node: List node for placing this node in the @queue list of 362965ebf33SHaavard Skinnemoen * &struct atmel_mci. 363965ebf33SHaavard Skinnemoen * @clock: Clock rate configured by set_ios(). Protected by host->lock. 364965ebf33SHaavard Skinnemoen * @flags: Random state bits associated with the slot. 365965ebf33SHaavard Skinnemoen * @detect_pin: GPIO pin used for card detection, or negative if not 366965ebf33SHaavard Skinnemoen * available. 367965ebf33SHaavard Skinnemoen * @wp_pin: GPIO pin used for card write protect sending, or negative 368965ebf33SHaavard Skinnemoen * if not available. 3691c1452beSJonas Larsson * @detect_is_active_high: The state of the detect pin when it is active. 370965ebf33SHaavard Skinnemoen * @detect_timer: Timer used for debouncing @detect_pin interrupts. 371965ebf33SHaavard Skinnemoen */ 372965ebf33SHaavard Skinnemoen struct atmel_mci_slot { 373965ebf33SHaavard Skinnemoen struct mmc_host *mmc; 374965ebf33SHaavard Skinnemoen struct atmel_mci *host; 375965ebf33SHaavard Skinnemoen 376965ebf33SHaavard Skinnemoen u32 sdc_reg; 37788ff82edSAnders Grahn u32 sdio_irq; 378965ebf33SHaavard Skinnemoen 379965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 380965ebf33SHaavard Skinnemoen struct list_head queue_node; 381965ebf33SHaavard Skinnemoen 382965ebf33SHaavard Skinnemoen unsigned int clock; 383965ebf33SHaavard Skinnemoen unsigned long flags; 384965ebf33SHaavard Skinnemoen #define ATMCI_CARD_PRESENT 0 385965ebf33SHaavard Skinnemoen #define ATMCI_CARD_NEED_INIT 1 386965ebf33SHaavard Skinnemoen #define ATMCI_SHUTDOWN 2 387965ebf33SHaavard Skinnemoen 388965ebf33SHaavard Skinnemoen int detect_pin; 389965ebf33SHaavard Skinnemoen int wp_pin; 3901c1452beSJonas Larsson bool detect_is_active_high; 391965ebf33SHaavard Skinnemoen 392965ebf33SHaavard Skinnemoen struct timer_list detect_timer; 3937d2be074SHaavard Skinnemoen }; 3947d2be074SHaavard Skinnemoen 3957d2be074SHaavard Skinnemoen #define atmci_test_and_clear_pending(host, event) \ 3967d2be074SHaavard Skinnemoen test_and_clear_bit(event, &host->pending_events) 3977d2be074SHaavard Skinnemoen #define atmci_set_completed(host, event) \ 3987d2be074SHaavard Skinnemoen set_bit(event, &host->completed_events) 3997d2be074SHaavard Skinnemoen #define atmci_set_pending(host, event) \ 4007d2be074SHaavard Skinnemoen set_bit(event, &host->pending_events) 4017d2be074SHaavard Skinnemoen 402deec9ae3SHaavard Skinnemoen /* 403deec9ae3SHaavard Skinnemoen * The debugfs stuff below is mostly optimized away when 404deec9ae3SHaavard Skinnemoen * CONFIG_DEBUG_FS is not set. 405deec9ae3SHaavard Skinnemoen */ 406deec9ae3SHaavard Skinnemoen static int atmci_req_show(struct seq_file *s, void *v) 407deec9ae3SHaavard Skinnemoen { 408965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = s->private; 409965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 410deec9ae3SHaavard Skinnemoen struct mmc_command *cmd; 411deec9ae3SHaavard Skinnemoen struct mmc_command *stop; 412deec9ae3SHaavard Skinnemoen struct mmc_data *data; 413deec9ae3SHaavard Skinnemoen 414deec9ae3SHaavard Skinnemoen /* Make sure we get a consistent snapshot */ 415965ebf33SHaavard Skinnemoen spin_lock_bh(&slot->host->lock); 416965ebf33SHaavard Skinnemoen mrq = slot->mrq; 417deec9ae3SHaavard Skinnemoen 418deec9ae3SHaavard Skinnemoen if (mrq) { 419deec9ae3SHaavard Skinnemoen cmd = mrq->cmd; 420deec9ae3SHaavard Skinnemoen data = mrq->data; 421deec9ae3SHaavard Skinnemoen stop = mrq->stop; 422deec9ae3SHaavard Skinnemoen 423deec9ae3SHaavard Skinnemoen if (cmd) 424deec9ae3SHaavard Skinnemoen seq_printf(s, 425deec9ae3SHaavard Skinnemoen "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 426deec9ae3SHaavard Skinnemoen cmd->opcode, cmd->arg, cmd->flags, 427deec9ae3SHaavard Skinnemoen cmd->resp[0], cmd->resp[1], cmd->resp[2], 428d586ebbbSNicolas Ferre cmd->resp[3], cmd->error); 429deec9ae3SHaavard Skinnemoen if (data) 430deec9ae3SHaavard Skinnemoen seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 431deec9ae3SHaavard Skinnemoen data->bytes_xfered, data->blocks, 432deec9ae3SHaavard Skinnemoen data->blksz, data->flags, data->error); 433deec9ae3SHaavard Skinnemoen if (stop) 434deec9ae3SHaavard Skinnemoen seq_printf(s, 435deec9ae3SHaavard Skinnemoen "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 436deec9ae3SHaavard Skinnemoen stop->opcode, stop->arg, stop->flags, 437deec9ae3SHaavard Skinnemoen stop->resp[0], stop->resp[1], stop->resp[2], 438d586ebbbSNicolas Ferre stop->resp[3], stop->error); 439deec9ae3SHaavard Skinnemoen } 440deec9ae3SHaavard Skinnemoen 441965ebf33SHaavard Skinnemoen spin_unlock_bh(&slot->host->lock); 442deec9ae3SHaavard Skinnemoen 443deec9ae3SHaavard Skinnemoen return 0; 444deec9ae3SHaavard Skinnemoen } 445deec9ae3SHaavard Skinnemoen 4468ceb2943SYangtao Li DEFINE_SHOW_ATTRIBUTE(atmci_req); 447deec9ae3SHaavard Skinnemoen 448deec9ae3SHaavard Skinnemoen static void atmci_show_status_reg(struct seq_file *s, 449deec9ae3SHaavard Skinnemoen const char *regname, u32 value) 450deec9ae3SHaavard Skinnemoen { 451deec9ae3SHaavard Skinnemoen static const char *sr_bit[] = { 452deec9ae3SHaavard Skinnemoen [0] = "CMDRDY", 453deec9ae3SHaavard Skinnemoen [1] = "RXRDY", 454deec9ae3SHaavard Skinnemoen [2] = "TXRDY", 455deec9ae3SHaavard Skinnemoen [3] = "BLKE", 456deec9ae3SHaavard Skinnemoen [4] = "DTIP", 457deec9ae3SHaavard Skinnemoen [5] = "NOTBUSY", 45804d699c3SRob Emanuele [6] = "ENDRX", 45904d699c3SRob Emanuele [7] = "ENDTX", 460deec9ae3SHaavard Skinnemoen [8] = "SDIOIRQA", 461deec9ae3SHaavard Skinnemoen [9] = "SDIOIRQB", 46204d699c3SRob Emanuele [12] = "SDIOWAIT", 46304d699c3SRob Emanuele [14] = "RXBUFF", 46404d699c3SRob Emanuele [15] = "TXBUFE", 465deec9ae3SHaavard Skinnemoen [16] = "RINDE", 466deec9ae3SHaavard Skinnemoen [17] = "RDIRE", 467deec9ae3SHaavard Skinnemoen [18] = "RCRCE", 468deec9ae3SHaavard Skinnemoen [19] = "RENDE", 469deec9ae3SHaavard Skinnemoen [20] = "RTOE", 470deec9ae3SHaavard Skinnemoen [21] = "DCRCE", 471deec9ae3SHaavard Skinnemoen [22] = "DTOE", 47204d699c3SRob Emanuele [23] = "CSTOE", 47304d699c3SRob Emanuele [24] = "BLKOVRE", 47404d699c3SRob Emanuele [25] = "DMADONE", 47504d699c3SRob Emanuele [26] = "FIFOEMPTY", 47604d699c3SRob Emanuele [27] = "XFRDONE", 477deec9ae3SHaavard Skinnemoen [30] = "OVRE", 478deec9ae3SHaavard Skinnemoen [31] = "UNRE", 479deec9ae3SHaavard Skinnemoen }; 480deec9ae3SHaavard Skinnemoen unsigned int i; 481deec9ae3SHaavard Skinnemoen 482deec9ae3SHaavard Skinnemoen seq_printf(s, "%s:\t0x%08x", regname, value); 483deec9ae3SHaavard Skinnemoen for (i = 0; i < ARRAY_SIZE(sr_bit); i++) { 484deec9ae3SHaavard Skinnemoen if (value & (1 << i)) { 485deec9ae3SHaavard Skinnemoen if (sr_bit[i]) 486deec9ae3SHaavard Skinnemoen seq_printf(s, " %s", sr_bit[i]); 487deec9ae3SHaavard Skinnemoen else 488deec9ae3SHaavard Skinnemoen seq_puts(s, " UNKNOWN"); 489deec9ae3SHaavard Skinnemoen } 490deec9ae3SHaavard Skinnemoen } 491deec9ae3SHaavard Skinnemoen seq_putc(s, '\n'); 492deec9ae3SHaavard Skinnemoen } 493deec9ae3SHaavard Skinnemoen 494deec9ae3SHaavard Skinnemoen static int atmci_regs_show(struct seq_file *s, void *v) 495deec9ae3SHaavard Skinnemoen { 496deec9ae3SHaavard Skinnemoen struct atmel_mci *host = s->private; 497deec9ae3SHaavard Skinnemoen u32 *buf; 498b3894f26SBoris BREZILLON int ret = 0; 499b3894f26SBoris BREZILLON 500deec9ae3SHaavard Skinnemoen 5012c96a293SLudovic Desroches buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL); 502deec9ae3SHaavard Skinnemoen if (!buf) 503deec9ae3SHaavard Skinnemoen return -ENOMEM; 504deec9ae3SHaavard Skinnemoen 505ae552ab0SWenyou Yang pm_runtime_get_sync(&host->pdev->dev); 506ae552ab0SWenyou Yang 507965ebf33SHaavard Skinnemoen /* 508965ebf33SHaavard Skinnemoen * Grab a more or less consistent snapshot. Note that we're 509965ebf33SHaavard Skinnemoen * not disabling interrupts, so IMR and SR may not be 510965ebf33SHaavard Skinnemoen * consistent. 511965ebf33SHaavard Skinnemoen */ 512965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 5132c96a293SLudovic Desroches memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); 514965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 515deec9ae3SHaavard Skinnemoen 516ae552ab0SWenyou Yang pm_runtime_mark_last_busy(&host->pdev->dev); 517ae552ab0SWenyou Yang pm_runtime_put_autosuspend(&host->pdev->dev); 518b3894f26SBoris BREZILLON 5198a4de07eSNicolas Ferre seq_printf(s, "MR:\t0x%08x%s%s ", 5202c96a293SLudovic Desroches buf[ATMCI_MR / 4], 5212c96a293SLudovic Desroches buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", 5228a4de07eSNicolas Ferre buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : ""); 5238a4de07eSNicolas Ferre if (host->caps.has_odd_clk_div) 5248a4de07eSNicolas Ferre seq_printf(s, "{CLKDIV,CLKODD}=%u\n", 5258a4de07eSNicolas Ferre ((buf[ATMCI_MR / 4] & 0xff) << 1) 5268a4de07eSNicolas Ferre | ((buf[ATMCI_MR / 4] >> 16) & 1)); 5278a4de07eSNicolas Ferre else 5288a4de07eSNicolas Ferre seq_printf(s, "CLKDIV=%u\n", 5298a4de07eSNicolas Ferre (buf[ATMCI_MR / 4] & 0xff)); 5302c96a293SLudovic Desroches seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]); 5312c96a293SLudovic Desroches seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); 5322c96a293SLudovic Desroches seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]); 533deec9ae3SHaavard Skinnemoen seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", 5342c96a293SLudovic Desroches buf[ATMCI_BLKR / 4], 5352c96a293SLudovic Desroches buf[ATMCI_BLKR / 4] & 0xffff, 5362c96a293SLudovic Desroches (buf[ATMCI_BLKR / 4] >> 16) & 0xffff); 537796211b7SLudovic Desroches if (host->caps.has_cstor_reg) 5382c96a293SLudovic Desroches seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]); 539deec9ae3SHaavard Skinnemoen 540deec9ae3SHaavard Skinnemoen /* Don't read RSPR and RDR; it will consume the data there */ 541deec9ae3SHaavard Skinnemoen 5422c96a293SLudovic Desroches atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]); 5432c96a293SLudovic Desroches atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]); 544deec9ae3SHaavard Skinnemoen 545ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) { 54674791a2dSNicolas Ferre u32 val; 54774791a2dSNicolas Ferre 5482c96a293SLudovic Desroches val = buf[ATMCI_DMA / 4]; 54974791a2dSNicolas Ferre seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n", 55074791a2dSNicolas Ferre val, val & 3, 55174791a2dSNicolas Ferre ((val >> 4) & 3) ? 55274791a2dSNicolas Ferre 1 << (((val >> 4) & 3) + 1) : 1, 5532c96a293SLudovic Desroches val & ATMCI_DMAEN ? " DMAEN" : ""); 554796211b7SLudovic Desroches } 555796211b7SLudovic Desroches if (host->caps.has_cfg_reg) { 556796211b7SLudovic Desroches u32 val; 55774791a2dSNicolas Ferre 5582c96a293SLudovic Desroches val = buf[ATMCI_CFG / 4]; 55974791a2dSNicolas Ferre seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n", 56074791a2dSNicolas Ferre val, 5612c96a293SLudovic Desroches val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", 5622c96a293SLudovic Desroches val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", 5632c96a293SLudovic Desroches val & ATMCI_CFG_HSMODE ? " HSMODE" : "", 5642c96a293SLudovic Desroches val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); 56574791a2dSNicolas Ferre } 56674791a2dSNicolas Ferre 567b17339a1SHaavard Skinnemoen kfree(buf); 568b17339a1SHaavard Skinnemoen 569b3894f26SBoris BREZILLON return ret; 570deec9ae3SHaavard Skinnemoen } 571deec9ae3SHaavard Skinnemoen 5728ceb2943SYangtao Li DEFINE_SHOW_ATTRIBUTE(atmci_regs); 573deec9ae3SHaavard Skinnemoen 574965ebf33SHaavard Skinnemoen static void atmci_init_debugfs(struct atmel_mci_slot *slot) 575deec9ae3SHaavard Skinnemoen { 576965ebf33SHaavard Skinnemoen struct mmc_host *mmc = slot->mmc; 577965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 578deec9ae3SHaavard Skinnemoen struct dentry *root; 579deec9ae3SHaavard Skinnemoen 580deec9ae3SHaavard Skinnemoen root = mmc->debugfs_root; 581deec9ae3SHaavard Skinnemoen if (!root) 582deec9ae3SHaavard Skinnemoen return; 583deec9ae3SHaavard Skinnemoen 584091eb12fSGreg Kroah-Hartman debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops); 585091eb12fSGreg Kroah-Hartman debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops); 586091eb12fSGreg Kroah-Hartman debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 587091eb12fSGreg Kroah-Hartman debugfs_create_x32("pending_events", S_IRUSR, root, 588deec9ae3SHaavard Skinnemoen (u32 *)&host->pending_events); 589091eb12fSGreg Kroah-Hartman debugfs_create_x32("completed_events", S_IRUSR, root, 590deec9ae3SHaavard Skinnemoen (u32 *)&host->completed_events); 591deec9ae3SHaavard Skinnemoen } 5927d2be074SHaavard Skinnemoen 593e919fd20SLudovic Desroches #if defined(CONFIG_OF) 594e919fd20SLudovic Desroches static const struct of_device_id atmci_dt_ids[] = { 595e919fd20SLudovic Desroches { .compatible = "atmel,hsmci" }, 596e919fd20SLudovic Desroches { /* sentinel */ } 597e919fd20SLudovic Desroches }; 598e919fd20SLudovic Desroches 599e919fd20SLudovic Desroches MODULE_DEVICE_TABLE(of, atmci_dt_ids); 600e919fd20SLudovic Desroches 601c3be1efdSBill Pemberton static struct mci_platform_data* 602e919fd20SLudovic Desroches atmci_of_init(struct platform_device *pdev) 603e919fd20SLudovic Desroches { 604e919fd20SLudovic Desroches struct device_node *np = pdev->dev.of_node; 605e919fd20SLudovic Desroches struct device_node *cnp; 606e919fd20SLudovic Desroches struct mci_platform_data *pdata; 607e919fd20SLudovic Desroches u32 slot_id; 608e919fd20SLudovic Desroches 609e919fd20SLudovic Desroches if (!np) { 610e919fd20SLudovic Desroches dev_err(&pdev->dev, "device node not found\n"); 611e919fd20SLudovic Desroches return ERR_PTR(-EINVAL); 612e919fd20SLudovic Desroches } 613e919fd20SLudovic Desroches 614e919fd20SLudovic Desroches pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 6159b344ba4SMarkus Elfring if (!pdata) 616e919fd20SLudovic Desroches return ERR_PTR(-ENOMEM); 617e919fd20SLudovic Desroches 618e919fd20SLudovic Desroches for_each_child_of_node(np, cnp) { 619e919fd20SLudovic Desroches if (of_property_read_u32(cnp, "reg", &slot_id)) { 620bf892de9SRob Herring dev_warn(&pdev->dev, "reg property is missing for %pOF\n", 621bf892de9SRob Herring cnp); 622e919fd20SLudovic Desroches continue; 623e919fd20SLudovic Desroches } 624e919fd20SLudovic Desroches 625e919fd20SLudovic Desroches if (slot_id >= ATMCI_MAX_NR_SLOTS) { 626e919fd20SLudovic Desroches dev_warn(&pdev->dev, "can't have more than %d slots\n", 627e919fd20SLudovic Desroches ATMCI_MAX_NR_SLOTS); 6287366419bSJulia Lawall of_node_put(cnp); 629e919fd20SLudovic Desroches break; 630e919fd20SLudovic Desroches } 631e919fd20SLudovic Desroches 632e919fd20SLudovic Desroches if (of_property_read_u32(cnp, "bus-width", 633e919fd20SLudovic Desroches &pdata->slot[slot_id].bus_width)) 634e919fd20SLudovic Desroches pdata->slot[slot_id].bus_width = 1; 635e919fd20SLudovic Desroches 636e919fd20SLudovic Desroches pdata->slot[slot_id].detect_pin = 637e919fd20SLudovic Desroches of_get_named_gpio(cnp, "cd-gpios", 0); 638e919fd20SLudovic Desroches 639e919fd20SLudovic Desroches pdata->slot[slot_id].detect_is_active_high = 640e919fd20SLudovic Desroches of_property_read_bool(cnp, "cd-inverted"); 641e919fd20SLudovic Desroches 64276d55564STimo Kokkonen pdata->slot[slot_id].non_removable = 64376d55564STimo Kokkonen of_property_read_bool(cnp, "non-removable"); 64476d55564STimo Kokkonen 645e919fd20SLudovic Desroches pdata->slot[slot_id].wp_pin = 646e919fd20SLudovic Desroches of_get_named_gpio(cnp, "wp-gpios", 0); 647e919fd20SLudovic Desroches } 648e919fd20SLudovic Desroches 649e919fd20SLudovic Desroches return pdata; 650e919fd20SLudovic Desroches } 651e919fd20SLudovic Desroches #else /* CONFIG_OF */ 652e919fd20SLudovic Desroches static inline struct mci_platform_data* 653e919fd20SLudovic Desroches atmci_of_init(struct platform_device *dev) 654e919fd20SLudovic Desroches { 655e919fd20SLudovic Desroches return ERR_PTR(-EINVAL); 656e919fd20SLudovic Desroches } 657e919fd20SLudovic Desroches #endif 658e919fd20SLudovic Desroches 6597a90dcc2SLudovic Desroches static inline unsigned int atmci_get_version(struct atmel_mci *host) 6607a90dcc2SLudovic Desroches { 6617a90dcc2SLudovic Desroches return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; 6627a90dcc2SLudovic Desroches } 6637a90dcc2SLudovic Desroches 664447dc0d2Sludovic.desroches@atmel.com /* 665447dc0d2Sludovic.desroches@atmel.com * Fix sconfig's burst size according to atmel MCI. We need to convert them as: 666447dc0d2Sludovic.desroches@atmel.com * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. 667447dc0d2Sludovic.desroches@atmel.com * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2, 668447dc0d2Sludovic.desroches@atmel.com * 8 -> 3, 16 -> 4. 669447dc0d2Sludovic.desroches@atmel.com * 670447dc0d2Sludovic.desroches@atmel.com * This can be done by finding most significant bit set. 671447dc0d2Sludovic.desroches@atmel.com */ 672447dc0d2Sludovic.desroches@atmel.com static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, 673447dc0d2Sludovic.desroches@atmel.com unsigned int maxburst) 674447dc0d2Sludovic.desroches@atmel.com { 675447dc0d2Sludovic.desroches@atmel.com unsigned int version = atmci_get_version(host); 676447dc0d2Sludovic.desroches@atmel.com unsigned int offset = 2; 677447dc0d2Sludovic.desroches@atmel.com 678447dc0d2Sludovic.desroches@atmel.com if (version >= 0x600) 679447dc0d2Sludovic.desroches@atmel.com offset = 1; 680447dc0d2Sludovic.desroches@atmel.com 681447dc0d2Sludovic.desroches@atmel.com if (maxburst > 1) 682447dc0d2Sludovic.desroches@atmel.com return fls(maxburst) - offset; 683447dc0d2Sludovic.desroches@atmel.com else 684447dc0d2Sludovic.desroches@atmel.com return 0; 685447dc0d2Sludovic.desroches@atmel.com } 686447dc0d2Sludovic.desroches@atmel.com 6872ee4f620SKees Cook static void atmci_timeout_timer(struct timer_list *t) 68824011f34SLudovic Desroches { 68924011f34SLudovic Desroches struct atmel_mci *host; 69024011f34SLudovic Desroches 6912ee4f620SKees Cook host = from_timer(host, t, timer); 69224011f34SLudovic Desroches 69324011f34SLudovic Desroches dev_dbg(&host->pdev->dev, "software timeout\n"); 69424011f34SLudovic Desroches 69524011f34SLudovic Desroches if (host->mrq->cmd->data) { 69624011f34SLudovic Desroches host->mrq->cmd->data->error = -ETIMEDOUT; 69724011f34SLudovic Desroches host->data = NULL; 698c1fa3426SLudovic Desroches /* 699c1fa3426SLudovic Desroches * With some SDIO modules, sometimes DMA transfer hangs. If 700c1fa3426SLudovic Desroches * stop_transfer() is not called then the DMA request is not 701c1fa3426SLudovic Desroches * removed, following ones are queued and never computed. 702c1fa3426SLudovic Desroches */ 703c1fa3426SLudovic Desroches if (host->state == STATE_DATA_XFER) 704c1fa3426SLudovic Desroches host->stop_transfer(host); 70524011f34SLudovic Desroches } else { 70624011f34SLudovic Desroches host->mrq->cmd->error = -ETIMEDOUT; 70724011f34SLudovic Desroches host->cmd = NULL; 70824011f34SLudovic Desroches } 70924011f34SLudovic Desroches host->need_reset = 1; 71024011f34SLudovic Desroches host->state = STATE_END_REQUEST; 71124011f34SLudovic Desroches smp_wmb(); 71224011f34SLudovic Desroches tasklet_schedule(&host->tasklet); 71324011f34SLudovic Desroches } 71424011f34SLudovic Desroches 7152c96a293SLudovic Desroches static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, 7167d2be074SHaavard Skinnemoen unsigned int ns) 7177d2be074SHaavard Skinnemoen { 71866292ad9SLudovic Desroches /* 71966292ad9SLudovic Desroches * It is easier here to use us instead of ns for the timeout, 72066292ad9SLudovic Desroches * it prevents from overflows during calculation. 72166292ad9SLudovic Desroches */ 72266292ad9SLudovic Desroches unsigned int us = DIV_ROUND_UP(ns, 1000); 72366292ad9SLudovic Desroches 72466292ad9SLudovic Desroches /* Maximum clock frequency is host->bus_hz/2 */ 72566292ad9SLudovic Desroches return us * (DIV_ROUND_UP(host->bus_hz, 2000000)); 7267d2be074SHaavard Skinnemoen } 7277d2be074SHaavard Skinnemoen 7287d2be074SHaavard Skinnemoen static void atmci_set_timeout(struct atmel_mci *host, 729965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot, struct mmc_data *data) 7307d2be074SHaavard Skinnemoen { 7317d2be074SHaavard Skinnemoen static unsigned dtomul_to_shift[] = { 7327d2be074SHaavard Skinnemoen 0, 4, 7, 8, 10, 12, 16, 20 7337d2be074SHaavard Skinnemoen }; 7347d2be074SHaavard Skinnemoen unsigned timeout; 7357d2be074SHaavard Skinnemoen unsigned dtocyc; 7367d2be074SHaavard Skinnemoen unsigned dtomul; 7377d2be074SHaavard Skinnemoen 7382c96a293SLudovic Desroches timeout = atmci_ns_to_clocks(host, data->timeout_ns) 7392c96a293SLudovic Desroches + data->timeout_clks; 7407d2be074SHaavard Skinnemoen 7417d2be074SHaavard Skinnemoen for (dtomul = 0; dtomul < 8; dtomul++) { 7427d2be074SHaavard Skinnemoen unsigned shift = dtomul_to_shift[dtomul]; 7437d2be074SHaavard Skinnemoen dtocyc = (timeout + (1 << shift) - 1) >> shift; 7447d2be074SHaavard Skinnemoen if (dtocyc < 15) 7457d2be074SHaavard Skinnemoen break; 7467d2be074SHaavard Skinnemoen } 7477d2be074SHaavard Skinnemoen 7487d2be074SHaavard Skinnemoen if (dtomul >= 8) { 7497d2be074SHaavard Skinnemoen dtomul = 7; 7507d2be074SHaavard Skinnemoen dtocyc = 15; 7517d2be074SHaavard Skinnemoen } 7527d2be074SHaavard Skinnemoen 753965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n", 7547d2be074SHaavard Skinnemoen dtocyc << dtomul_to_shift[dtomul]); 75503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); 7567d2be074SHaavard Skinnemoen } 7577d2be074SHaavard Skinnemoen 7587d2be074SHaavard Skinnemoen /* 7597d2be074SHaavard Skinnemoen * Return mask with command flags to be enabled for this command. 7607d2be074SHaavard Skinnemoen */ 7617d2be074SHaavard Skinnemoen static u32 atmci_prepare_command(struct mmc_host *mmc, 7627d2be074SHaavard Skinnemoen struct mmc_command *cmd) 7637d2be074SHaavard Skinnemoen { 7647d2be074SHaavard Skinnemoen struct mmc_data *data; 7657d2be074SHaavard Skinnemoen u32 cmdr; 7667d2be074SHaavard Skinnemoen 7677d2be074SHaavard Skinnemoen cmd->error = -EINPROGRESS; 7687d2be074SHaavard Skinnemoen 7692c96a293SLudovic Desroches cmdr = ATMCI_CMDR_CMDNB(cmd->opcode); 7707d2be074SHaavard Skinnemoen 7717d2be074SHaavard Skinnemoen if (cmd->flags & MMC_RSP_PRESENT) { 7727d2be074SHaavard Skinnemoen if (cmd->flags & MMC_RSP_136) 7732c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_RSPTYP_136BIT; 7747d2be074SHaavard Skinnemoen else 7752c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_RSPTYP_48BIT; 7767d2be074SHaavard Skinnemoen } 7777d2be074SHaavard Skinnemoen 7787d2be074SHaavard Skinnemoen /* 7797d2be074SHaavard Skinnemoen * This should really be MAXLAT_5 for CMD2 and ACMD41, but 7807d2be074SHaavard Skinnemoen * it's too difficult to determine whether this is an ACMD or 7817d2be074SHaavard Skinnemoen * not. Better make it 64. 7827d2be074SHaavard Skinnemoen */ 7832c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_MAXLAT_64CYC; 7847d2be074SHaavard Skinnemoen 7857d2be074SHaavard Skinnemoen if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) 7862c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_OPDCMD; 7877d2be074SHaavard Skinnemoen 7887d2be074SHaavard Skinnemoen data = cmd->data; 7897d2be074SHaavard Skinnemoen if (data) { 7902c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_START_XFER; 7912f1d7918SNicolas Ferre 7922f1d7918SNicolas Ferre if (cmd->opcode == SD_IO_RW_EXTENDED) { 7932c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_SDIO_BLOCK; 7942f1d7918SNicolas Ferre } else { 795fd551d94SJaehoon Chung if (data->blocks > 1) 7962c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_MULTI_BLOCK; 7977d2be074SHaavard Skinnemoen else 7982c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_BLOCK; 7992f1d7918SNicolas Ferre } 8007d2be074SHaavard Skinnemoen 8017d2be074SHaavard Skinnemoen if (data->flags & MMC_DATA_READ) 8022c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_TRDIR_READ; 8037d2be074SHaavard Skinnemoen } 8047d2be074SHaavard Skinnemoen 8057d2be074SHaavard Skinnemoen return cmdr; 8067d2be074SHaavard Skinnemoen } 8077d2be074SHaavard Skinnemoen 80811d1488bSLudovic Desroches static void atmci_send_command(struct atmel_mci *host, 809965ebf33SHaavard Skinnemoen struct mmc_command *cmd, u32 cmd_flags) 8107d2be074SHaavard Skinnemoen { 8117d2be074SHaavard Skinnemoen WARN_ON(host->cmd); 8127d2be074SHaavard Skinnemoen host->cmd = cmd; 8137d2be074SHaavard Skinnemoen 814965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, 8157d2be074SHaavard Skinnemoen "start command: ARGR=0x%08x CMDR=0x%08x\n", 8167d2be074SHaavard Skinnemoen cmd->arg, cmd_flags); 8177d2be074SHaavard Skinnemoen 81803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_ARGR, cmd->arg); 81903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CMDR, cmd_flags); 8207d2be074SHaavard Skinnemoen } 8217d2be074SHaavard Skinnemoen 8222c96a293SLudovic Desroches static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) 8237d2be074SHaavard Skinnemoen { 8246801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "send stop command\n"); 82511d1488bSLudovic Desroches atmci_send_command(host, data->stop, host->stop_cmdr); 82603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); 8277d2be074SHaavard Skinnemoen } 8287d2be074SHaavard Skinnemoen 829796211b7SLudovic Desroches /* 830796211b7SLudovic Desroches * Configure given PDC buffer taking care of alignement issues. 831796211b7SLudovic Desroches * Update host->data_size and host->sg. 832796211b7SLudovic Desroches */ 833796211b7SLudovic Desroches static void atmci_pdc_set_single_buf(struct atmel_mci *host, 834796211b7SLudovic Desroches enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) 835796211b7SLudovic Desroches { 836796211b7SLudovic Desroches u32 pointer_reg, counter_reg; 8377a90dcc2SLudovic Desroches unsigned int buf_size; 838796211b7SLudovic Desroches 839796211b7SLudovic Desroches if (dir == XFER_RECEIVE) { 840796211b7SLudovic Desroches pointer_reg = ATMEL_PDC_RPR; 841796211b7SLudovic Desroches counter_reg = ATMEL_PDC_RCR; 842796211b7SLudovic Desroches } else { 843796211b7SLudovic Desroches pointer_reg = ATMEL_PDC_TPR; 844796211b7SLudovic Desroches counter_reg = ATMEL_PDC_TCR; 845796211b7SLudovic Desroches } 846796211b7SLudovic Desroches 847796211b7SLudovic Desroches if (buf_nb == PDC_SECOND_BUF) { 8481ebbe3d3SLudovic Desroches pointer_reg += ATMEL_PDC_SCND_BUF_OFF; 8491ebbe3d3SLudovic Desroches counter_reg += ATMEL_PDC_SCND_BUF_OFF; 850796211b7SLudovic Desroches } 851796211b7SLudovic Desroches 8527a90dcc2SLudovic Desroches if (!host->caps.has_rwproof) { 8537a90dcc2SLudovic Desroches buf_size = host->buf_size; 8547a90dcc2SLudovic Desroches atmci_writel(host, pointer_reg, host->buf_phys_addr); 8557a90dcc2SLudovic Desroches } else { 8567a90dcc2SLudovic Desroches buf_size = sg_dma_len(host->sg); 857796211b7SLudovic Desroches atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); 8587a90dcc2SLudovic Desroches } 8597a90dcc2SLudovic Desroches 8607a90dcc2SLudovic Desroches if (host->data_size <= buf_size) { 861796211b7SLudovic Desroches if (host->data_size & 0x3) { 862796211b7SLudovic Desroches /* If size is different from modulo 4, transfer bytes */ 863796211b7SLudovic Desroches atmci_writel(host, counter_reg, host->data_size); 864796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE); 865796211b7SLudovic Desroches } else { 866796211b7SLudovic Desroches /* Else transfer 32-bits words */ 867796211b7SLudovic Desroches atmci_writel(host, counter_reg, host->data_size / 4); 868796211b7SLudovic Desroches } 869796211b7SLudovic Desroches host->data_size = 0; 870796211b7SLudovic Desroches } else { 871796211b7SLudovic Desroches /* We assume the size of a page is 32-bits aligned */ 872341fa4c3SLudovic Desroches atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4); 873341fa4c3SLudovic Desroches host->data_size -= sg_dma_len(host->sg); 874796211b7SLudovic Desroches if (host->data_size) 875796211b7SLudovic Desroches host->sg = sg_next(host->sg); 876796211b7SLudovic Desroches } 877796211b7SLudovic Desroches } 878796211b7SLudovic Desroches 879796211b7SLudovic Desroches /* 880796211b7SLudovic Desroches * Configure PDC buffer according to the data size ie configuring one or two 881796211b7SLudovic Desroches * buffers. Don't use this function if you want to configure only the second 882796211b7SLudovic Desroches * buffer. In this case, use atmci_pdc_set_single_buf. 883796211b7SLudovic Desroches */ 884796211b7SLudovic Desroches static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir) 885796211b7SLudovic Desroches { 886796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF); 887796211b7SLudovic Desroches if (host->data_size) 888796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF); 889796211b7SLudovic Desroches } 890796211b7SLudovic Desroches 891796211b7SLudovic Desroches /* 892796211b7SLudovic Desroches * Unmap sg lists, called when transfer is finished. 893796211b7SLudovic Desroches */ 894796211b7SLudovic Desroches static void atmci_pdc_cleanup(struct atmel_mci *host) 895796211b7SLudovic Desroches { 896796211b7SLudovic Desroches struct mmc_data *data = host->data; 897796211b7SLudovic Desroches 898796211b7SLudovic Desroches if (data) 899796211b7SLudovic Desroches dma_unmap_sg(&host->pdev->dev, 900796211b7SLudovic Desroches data->sg, data->sg_len, 901feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 902796211b7SLudovic Desroches } 903796211b7SLudovic Desroches 904796211b7SLudovic Desroches /* 905796211b7SLudovic Desroches * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after 906796211b7SLudovic Desroches * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY 907796211b7SLudovic Desroches * interrupt needed for both transfer directions. 908796211b7SLudovic Desroches */ 909796211b7SLudovic Desroches static void atmci_pdc_complete(struct atmel_mci *host) 910796211b7SLudovic Desroches { 9117a90dcc2SLudovic Desroches int transfer_size = host->data->blocks * host->data->blksz; 91224011f34SLudovic Desroches int i; 9137a90dcc2SLudovic Desroches 914796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); 9157a90dcc2SLudovic Desroches 9167a90dcc2SLudovic Desroches if ((!host->caps.has_rwproof) 91724011f34SLudovic Desroches && (host->data->flags & MMC_DATA_READ)) { 91824011f34SLudovic Desroches if (host->caps.has_bad_data_ordering) 91924011f34SLudovic Desroches for (i = 0; i < transfer_size; i++) 92024011f34SLudovic Desroches host->buffer[i] = swab32(host->buffer[i]); 9217a90dcc2SLudovic Desroches sg_copy_from_buffer(host->data->sg, host->data->sg_len, 9227a90dcc2SLudovic Desroches host->buffer, transfer_size); 92324011f34SLudovic Desroches } 9247a90dcc2SLudovic Desroches 925796211b7SLudovic Desroches atmci_pdc_cleanup(host); 926796211b7SLudovic Desroches 9276e9e4062SAlexandre Belloni dev_dbg(&host->pdev->dev, "(%s) set pending xfer complete\n", __func__); 928796211b7SLudovic Desroches atmci_set_pending(host, EVENT_XFER_COMPLETE); 929796211b7SLudovic Desroches tasklet_schedule(&host->tasklet); 930796211b7SLudovic Desroches } 931796211b7SLudovic Desroches 93265e8b083SHaavard Skinnemoen static void atmci_dma_cleanup(struct atmel_mci *host) 93365e8b083SHaavard Skinnemoen { 93465e8b083SHaavard Skinnemoen struct mmc_data *data = host->data; 93565e8b083SHaavard Skinnemoen 936009a891bSNicolas Ferre if (data) 937266ac3f2SLinus Walleij dma_unmap_sg(host->dma.chan->device->dev, 938266ac3f2SLinus Walleij data->sg, data->sg_len, 939feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 94065e8b083SHaavard Skinnemoen } 94165e8b083SHaavard Skinnemoen 942796211b7SLudovic Desroches /* 943796211b7SLudovic Desroches * This function is called by the DMA driver from tasklet context. 944796211b7SLudovic Desroches */ 94565e8b083SHaavard Skinnemoen static void atmci_dma_complete(void *arg) 94665e8b083SHaavard Skinnemoen { 94765e8b083SHaavard Skinnemoen struct atmel_mci *host = arg; 94865e8b083SHaavard Skinnemoen struct mmc_data *data = host->data; 94965e8b083SHaavard Skinnemoen 95065e8b083SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "DMA complete\n"); 95165e8b083SHaavard Skinnemoen 952ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) 95374791a2dSNicolas Ferre /* Disable DMA hardware handshaking on MCI */ 95403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); 95574791a2dSNicolas Ferre 95665e8b083SHaavard Skinnemoen atmci_dma_cleanup(host); 95765e8b083SHaavard Skinnemoen 95865e8b083SHaavard Skinnemoen /* 95965e8b083SHaavard Skinnemoen * If the card was removed, data will be NULL. No point trying 96065e8b083SHaavard Skinnemoen * to send the stop command or waiting for NBUSY in this case. 96165e8b083SHaavard Skinnemoen */ 96265e8b083SHaavard Skinnemoen if (data) { 9636801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 9646801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 96565e8b083SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 96665e8b083SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 96765e8b083SHaavard Skinnemoen 96865e8b083SHaavard Skinnemoen /* 96965e8b083SHaavard Skinnemoen * Regardless of what the documentation says, we have 97065e8b083SHaavard Skinnemoen * to wait for NOTBUSY even after block read 97165e8b083SHaavard Skinnemoen * operations. 97265e8b083SHaavard Skinnemoen * 97365e8b083SHaavard Skinnemoen * When the DMA transfer is complete, the controller 97465e8b083SHaavard Skinnemoen * may still be reading the CRC from the card, i.e. 97565e8b083SHaavard Skinnemoen * the data transfer is still in progress and we 97665e8b083SHaavard Skinnemoen * haven't seen all the potential error bits yet. 97765e8b083SHaavard Skinnemoen * 97865e8b083SHaavard Skinnemoen * The interrupt handler will schedule a different 97965e8b083SHaavard Skinnemoen * tasklet to finish things up when the data transfer 98065e8b083SHaavard Skinnemoen * is completely done. 98165e8b083SHaavard Skinnemoen * 98265e8b083SHaavard Skinnemoen * We may not complete the mmc request here anyway 98365e8b083SHaavard Skinnemoen * because the mmc layer may call back and cause us to 98465e8b083SHaavard Skinnemoen * violate the "don't submit new operations from the 98565e8b083SHaavard Skinnemoen * completion callback" rule of the dma engine 98665e8b083SHaavard Skinnemoen * framework. 98765e8b083SHaavard Skinnemoen */ 98803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 98965e8b083SHaavard Skinnemoen } 99065e8b083SHaavard Skinnemoen } 99165e8b083SHaavard Skinnemoen 992796211b7SLudovic Desroches /* 993796211b7SLudovic Desroches * Returns a mask of interrupt flags to be enabled after the whole 994796211b7SLudovic Desroches * request has been prepared. 995796211b7SLudovic Desroches */ 996796211b7SLudovic Desroches static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) 997796211b7SLudovic Desroches { 998796211b7SLudovic Desroches u32 iflags; 999796211b7SLudovic Desroches 1000796211b7SLudovic Desroches data->error = -EINPROGRESS; 1001796211b7SLudovic Desroches 1002796211b7SLudovic Desroches host->sg = data->sg; 1003bdbc5d0cSTerry Barnaby host->sg_len = data->sg_len; 1004796211b7SLudovic Desroches host->data = data; 1005796211b7SLudovic Desroches host->data_chan = NULL; 1006796211b7SLudovic Desroches 1007796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 1008796211b7SLudovic Desroches 1009796211b7SLudovic Desroches /* 1010796211b7SLudovic Desroches * Errata: MMC data write operation with less than 12 1011796211b7SLudovic Desroches * bytes is impossible. 1012796211b7SLudovic Desroches * 1013796211b7SLudovic Desroches * Errata: MCI Transmit Data Register (TDR) FIFO 1014796211b7SLudovic Desroches * corruption when length is not multiple of 4. 1015796211b7SLudovic Desroches */ 1016796211b7SLudovic Desroches if (data->blocks * data->blksz < 12 1017796211b7SLudovic Desroches || (data->blocks * data->blksz) & 3) 1018796211b7SLudovic Desroches host->need_reset = true; 1019796211b7SLudovic Desroches 1020796211b7SLudovic Desroches host->pio_offset = 0; 1021796211b7SLudovic Desroches if (data->flags & MMC_DATA_READ) 1022796211b7SLudovic Desroches iflags |= ATMCI_RXRDY; 1023796211b7SLudovic Desroches else 1024796211b7SLudovic Desroches iflags |= ATMCI_TXRDY; 1025796211b7SLudovic Desroches 1026796211b7SLudovic Desroches return iflags; 1027796211b7SLudovic Desroches } 1028796211b7SLudovic Desroches 1029796211b7SLudovic Desroches /* 1030796211b7SLudovic Desroches * Set interrupt flags and set block length into the MCI mode register even 1031796211b7SLudovic Desroches * if this value is also accessible in the MCI block register. It seems to be 1032796211b7SLudovic Desroches * necessary before the High Speed MCI version. It also map sg and configure 1033796211b7SLudovic Desroches * PDC registers. 1034796211b7SLudovic Desroches */ 1035796211b7SLudovic Desroches static u32 1036796211b7SLudovic Desroches atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) 1037796211b7SLudovic Desroches { 1038796211b7SLudovic Desroches u32 iflags, tmp; 103924011f34SLudovic Desroches int i; 1040796211b7SLudovic Desroches 1041796211b7SLudovic Desroches data->error = -EINPROGRESS; 1042796211b7SLudovic Desroches 1043796211b7SLudovic Desroches host->data = data; 1044796211b7SLudovic Desroches host->sg = data->sg; 1045796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 1046796211b7SLudovic Desroches 1047796211b7SLudovic Desroches /* Enable pdc mode */ 1048796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE); 1049796211b7SLudovic Desroches 1050feeef096SHeiner Kallweit if (data->flags & MMC_DATA_READ) 1051796211b7SLudovic Desroches iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; 1052feeef096SHeiner Kallweit else 1053f5177547SLudovic Desroches iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; 1054796211b7SLudovic Desroches 1055796211b7SLudovic Desroches /* Set BLKLEN */ 1056796211b7SLudovic Desroches tmp = atmci_readl(host, ATMCI_MR); 1057796211b7SLudovic Desroches tmp &= 0x0000ffff; 1058796211b7SLudovic Desroches tmp |= ATMCI_BLKLEN(data->blksz); 1059796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, tmp); 1060796211b7SLudovic Desroches 1061796211b7SLudovic Desroches /* Configure PDC */ 1062796211b7SLudovic Desroches host->data_size = data->blocks * data->blksz; 1063f98e0d5aSShawn Lin dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, 1064feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 10657a90dcc2SLudovic Desroches 10667a90dcc2SLudovic Desroches if ((!host->caps.has_rwproof) 106724011f34SLudovic Desroches && (host->data->flags & MMC_DATA_WRITE)) { 10687a90dcc2SLudovic Desroches sg_copy_to_buffer(host->data->sg, host->data->sg_len, 10697a90dcc2SLudovic Desroches host->buffer, host->data_size); 107024011f34SLudovic Desroches if (host->caps.has_bad_data_ordering) 107124011f34SLudovic Desroches for (i = 0; i < host->data_size; i++) 107224011f34SLudovic Desroches host->buffer[i] = swab32(host->buffer[i]); 107324011f34SLudovic Desroches } 10747a90dcc2SLudovic Desroches 1075796211b7SLudovic Desroches if (host->data_size) 1076feeef096SHeiner Kallweit atmci_pdc_set_both_buf(host, data->flags & MMC_DATA_READ ? 1077feeef096SHeiner Kallweit XFER_RECEIVE : XFER_TRANSMIT); 1078796211b7SLudovic Desroches return iflags; 1079796211b7SLudovic Desroches } 1080796211b7SLudovic Desroches 1081796211b7SLudovic Desroches static u32 108274791a2dSNicolas Ferre atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) 108365e8b083SHaavard Skinnemoen { 108465e8b083SHaavard Skinnemoen struct dma_chan *chan; 108565e8b083SHaavard Skinnemoen struct dma_async_tx_descriptor *desc; 108665e8b083SHaavard Skinnemoen struct scatterlist *sg; 108765e8b083SHaavard Skinnemoen unsigned int i; 108805f5799cSVinod Koul enum dma_transfer_direction slave_dirn; 1089657a77faSAtsushi Nemoto unsigned int sglen; 1090693e5e20SNicolas Ferre u32 maxburst; 1091796211b7SLudovic Desroches u32 iflags; 1092796211b7SLudovic Desroches 1093796211b7SLudovic Desroches data->error = -EINPROGRESS; 1094796211b7SLudovic Desroches 1095796211b7SLudovic Desroches WARN_ON(host->data); 1096796211b7SLudovic Desroches host->sg = NULL; 1097796211b7SLudovic Desroches host->data = data; 1098796211b7SLudovic Desroches 1099796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 110065e8b083SHaavard Skinnemoen 110165e8b083SHaavard Skinnemoen /* 110265e8b083SHaavard Skinnemoen * We don't do DMA on "complex" transfers, i.e. with 110365e8b083SHaavard Skinnemoen * non-word-aligned buffers or lengths. Also, we don't bother 110465e8b083SHaavard Skinnemoen * with all the DMA setup overhead for short transfers. 110565e8b083SHaavard Skinnemoen */ 1106796211b7SLudovic Desroches if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) 1107796211b7SLudovic Desroches return atmci_prepare_data(host, data); 110865e8b083SHaavard Skinnemoen if (data->blksz & 3) 1109796211b7SLudovic Desroches return atmci_prepare_data(host, data); 111065e8b083SHaavard Skinnemoen 111165e8b083SHaavard Skinnemoen for_each_sg(data->sg, sg, data->sg_len, i) { 111265e8b083SHaavard Skinnemoen if (sg->offset & 3 || sg->length & 3) 1113796211b7SLudovic Desroches return atmci_prepare_data(host, data); 111465e8b083SHaavard Skinnemoen } 111565e8b083SHaavard Skinnemoen 111665e8b083SHaavard Skinnemoen /* If we don't have a channel, we can't do DMA */ 111765e8b083SHaavard Skinnemoen chan = host->dma.chan; 11186f49a57aSDan Williams if (chan) 111965e8b083SHaavard Skinnemoen host->data_chan = chan; 112065e8b083SHaavard Skinnemoen 112165e8b083SHaavard Skinnemoen if (!chan) 112265e8b083SHaavard Skinnemoen return -ENODEV; 112365e8b083SHaavard Skinnemoen 112405f5799cSVinod Koul if (data->flags & MMC_DATA_READ) { 1125e2b35f3dSViresh Kumar host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; 1126447dc0d2Sludovic.desroches@atmel.com maxburst = atmci_convert_chksize(host, 1127447dc0d2Sludovic.desroches@atmel.com host->dma_conf.src_maxburst); 112805f5799cSVinod Koul } else { 1129e2b35f3dSViresh Kumar host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; 1130447dc0d2Sludovic.desroches@atmel.com maxburst = atmci_convert_chksize(host, 1131447dc0d2Sludovic.desroches@atmel.com host->dma_conf.dst_maxburst); 113205f5799cSVinod Koul } 113365e8b083SHaavard Skinnemoen 1134ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) 1135ccdfe612SHein_Tibosch atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | 1136ccdfe612SHein_Tibosch ATMCI_DMAEN); 1137693e5e20SNicolas Ferre 1138266ac3f2SLinus Walleij sglen = dma_map_sg(chan->device->dev, data->sg, 1139feeef096SHeiner Kallweit data->sg_len, mmc_get_dma_dir(data)); 114088ce4db3SLinus Walleij 1141e2b35f3dSViresh Kumar dmaengine_slave_config(chan, &host->dma_conf); 114216052827SAlexandre Bounine desc = dmaengine_prep_slave_sg(chan, 114305f5799cSVinod Koul data->sg, sglen, slave_dirn, 114465e8b083SHaavard Skinnemoen DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 114565e8b083SHaavard Skinnemoen if (!desc) 1146657a77faSAtsushi Nemoto goto unmap_exit; 114765e8b083SHaavard Skinnemoen 114865e8b083SHaavard Skinnemoen host->dma.data_desc = desc; 114965e8b083SHaavard Skinnemoen desc->callback = atmci_dma_complete; 115065e8b083SHaavard Skinnemoen desc->callback_param = host; 115165e8b083SHaavard Skinnemoen 1152796211b7SLudovic Desroches return iflags; 1153657a77faSAtsushi Nemoto unmap_exit: 1154feeef096SHeiner Kallweit dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, 1155feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 1156657a77faSAtsushi Nemoto return -ENOMEM; 115765e8b083SHaavard Skinnemoen } 115865e8b083SHaavard Skinnemoen 1159796211b7SLudovic Desroches static void 1160796211b7SLudovic Desroches atmci_submit_data(struct atmel_mci *host, struct mmc_data *data) 1161796211b7SLudovic Desroches { 1162796211b7SLudovic Desroches return; 1163796211b7SLudovic Desroches } 1164796211b7SLudovic Desroches 1165796211b7SLudovic Desroches /* 1166796211b7SLudovic Desroches * Start PDC according to transfer direction. 1167796211b7SLudovic Desroches */ 1168796211b7SLudovic Desroches static void 1169796211b7SLudovic Desroches atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data) 1170796211b7SLudovic Desroches { 1171796211b7SLudovic Desroches if (data->flags & MMC_DATA_READ) 1172796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); 1173796211b7SLudovic Desroches else 1174796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); 1175796211b7SLudovic Desroches } 1176796211b7SLudovic Desroches 1177796211b7SLudovic Desroches static void 1178796211b7SLudovic Desroches atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) 117974791a2dSNicolas Ferre { 118074791a2dSNicolas Ferre struct dma_chan *chan = host->data_chan; 118174791a2dSNicolas Ferre struct dma_async_tx_descriptor *desc = host->dma.data_desc; 118274791a2dSNicolas Ferre 118374791a2dSNicolas Ferre if (chan) { 11845328906aSLinus Walleij dmaengine_submit(desc); 11855328906aSLinus Walleij dma_async_issue_pending(chan); 118674791a2dSNicolas Ferre } 118774791a2dSNicolas Ferre } 118874791a2dSNicolas Ferre 1189796211b7SLudovic Desroches static void atmci_stop_transfer(struct atmel_mci *host) 119065e8b083SHaavard Skinnemoen { 11916801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 11926801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 119365e8b083SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 119403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 119565e8b083SHaavard Skinnemoen } 119665e8b083SHaavard Skinnemoen 11977d2be074SHaavard Skinnemoen /* 11987122bbb0SMasanari Iida * Stop data transfer because error(s) occurred. 11997d2be074SHaavard Skinnemoen */ 1200796211b7SLudovic Desroches static void atmci_stop_transfer_pdc(struct atmel_mci *host) 12017d2be074SHaavard Skinnemoen { 1202f5177547SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); 1203796211b7SLudovic Desroches } 12047d2be074SHaavard Skinnemoen 1205796211b7SLudovic Desroches static void atmci_stop_transfer_dma(struct atmel_mci *host) 1206796211b7SLudovic Desroches { 1207796211b7SLudovic Desroches struct dma_chan *chan = host->data_chan; 12087d2be074SHaavard Skinnemoen 1209796211b7SLudovic Desroches if (chan) { 1210796211b7SLudovic Desroches dmaengine_terminate_all(chan); 1211796211b7SLudovic Desroches atmci_dma_cleanup(host); 1212796211b7SLudovic Desroches } else { 1213796211b7SLudovic Desroches /* Data transfer was stopped by the interrupt handler */ 12146801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 12156801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 1216796211b7SLudovic Desroches atmci_set_pending(host, EVENT_XFER_COMPLETE); 1217796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1218796211b7SLudovic Desroches } 1219796211b7SLudovic Desroches } 1220965ebf33SHaavard Skinnemoen 1221965ebf33SHaavard Skinnemoen /* 1222796211b7SLudovic Desroches * Start a request: prepare data if needed, prepare the command and activate 1223796211b7SLudovic Desroches * interrupts. 1224965ebf33SHaavard Skinnemoen */ 1225965ebf33SHaavard Skinnemoen static void atmci_start_request(struct atmel_mci *host, 1226965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot) 12277d2be074SHaavard Skinnemoen { 1228965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 12297d2be074SHaavard Skinnemoen struct mmc_command *cmd; 1230965ebf33SHaavard Skinnemoen struct mmc_data *data; 12317d2be074SHaavard Skinnemoen u32 iflags; 1232965ebf33SHaavard Skinnemoen u32 cmdflags; 1233965ebf33SHaavard Skinnemoen 1234965ebf33SHaavard Skinnemoen mrq = slot->mrq; 1235965ebf33SHaavard Skinnemoen host->cur_slot = slot; 1236965ebf33SHaavard Skinnemoen host->mrq = mrq; 1237965ebf33SHaavard Skinnemoen 1238965ebf33SHaavard Skinnemoen host->pending_events = 0; 1239965ebf33SHaavard Skinnemoen host->completed_events = 0; 1240f5177547SLudovic Desroches host->cmd_status = 0; 1241ca55f46eSHaavard Skinnemoen host->data_status = 0; 1242965ebf33SHaavard Skinnemoen 12436801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode); 12446801c41aSLudovic Desroches 124524011f34SLudovic Desroches if (host->need_reset || host->caps.need_reset_after_xfer) { 124618ee684bSLudovic Desroches iflags = atmci_readl(host, ATMCI_IMR); 124718ee684bSLudovic Desroches iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); 124803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 124903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 125003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1251796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 125203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 125318ee684bSLudovic Desroches atmci_writel(host, ATMCI_IER, iflags); 1254965ebf33SHaavard Skinnemoen host->need_reset = false; 1255965ebf33SHaavard Skinnemoen } 125603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); 12577d2be074SHaavard Skinnemoen 125803fc9a7fSLudovic Desroches iflags = atmci_readl(host, ATMCI_IMR); 12592c96a293SLudovic Desroches if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) 1260f5177547SLudovic Desroches dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", 1261965ebf33SHaavard Skinnemoen iflags); 12627d2be074SHaavard Skinnemoen 1263965ebf33SHaavard Skinnemoen if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { 1264965ebf33SHaavard Skinnemoen /* Send init sequence (74 clock cycles) */ 126503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); 126603fc9a7fSLudovic Desroches while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY)) 1267965ebf33SHaavard Skinnemoen cpu_relax(); 12687d2be074SHaavard Skinnemoen } 126974791a2dSNicolas Ferre iflags = 0; 12707d2be074SHaavard Skinnemoen data = mrq->data; 12717d2be074SHaavard Skinnemoen if (data) { 1272965ebf33SHaavard Skinnemoen atmci_set_timeout(host, slot, data); 1273a252e3e3SHaavard Skinnemoen 1274a252e3e3SHaavard Skinnemoen /* Must set block count/size before sending command */ 127503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) 12762c96a293SLudovic Desroches | ATMCI_BLKLEN(data->blksz)); 1277965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", 12782c96a293SLudovic Desroches ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); 127974791a2dSNicolas Ferre 1280796211b7SLudovic Desroches iflags |= host->prepare_data(host, data); 12817d2be074SHaavard Skinnemoen } 12827d2be074SHaavard Skinnemoen 12832c96a293SLudovic Desroches iflags |= ATMCI_CMDRDY; 12847d2be074SHaavard Skinnemoen cmd = mrq->cmd; 1285965ebf33SHaavard Skinnemoen cmdflags = atmci_prepare_command(slot->mmc, cmd); 128666b512edSLudovic Desroches 128766b512edSLudovic Desroches /* 128866b512edSLudovic Desroches * DMA transfer should be started before sending the command to avoid 128966b512edSLudovic Desroches * unexpected errors especially for read operations in SDIO mode. 129066b512edSLudovic Desroches * Unfortunately, in PDC mode, command has to be sent before starting 129166b512edSLudovic Desroches * the transfer. 129266b512edSLudovic Desroches */ 129366b512edSLudovic Desroches if (host->submit_data != &atmci_submit_data_dma) 129411d1488bSLudovic Desroches atmci_send_command(host, cmd, cmdflags); 12957d2be074SHaavard Skinnemoen 12967d2be074SHaavard Skinnemoen if (data) 1297796211b7SLudovic Desroches host->submit_data(host, data); 12987d2be074SHaavard Skinnemoen 129966b512edSLudovic Desroches if (host->submit_data == &atmci_submit_data_dma) 130066b512edSLudovic Desroches atmci_send_command(host, cmd, cmdflags); 130166b512edSLudovic Desroches 13027d2be074SHaavard Skinnemoen if (mrq->stop) { 1303965ebf33SHaavard Skinnemoen host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); 13042c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; 13057d2be074SHaavard Skinnemoen if (!(data->flags & MMC_DATA_WRITE)) 13062c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; 13072c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; 13087d2be074SHaavard Skinnemoen } 13097d2be074SHaavard Skinnemoen 13107d2be074SHaavard Skinnemoen /* 13117d2be074SHaavard Skinnemoen * We could have enabled interrupts earlier, but I suspect 13127d2be074SHaavard Skinnemoen * that would open up a nice can of interesting race 13137d2be074SHaavard Skinnemoen * conditions (e.g. command and data complete, but stop not 13147d2be074SHaavard Skinnemoen * prepared yet.) 13157d2be074SHaavard Skinnemoen */ 131603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, iflags); 131724011f34SLudovic Desroches 131824011f34SLudovic Desroches mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); 1319965ebf33SHaavard Skinnemoen } 13207d2be074SHaavard Skinnemoen 1321965ebf33SHaavard Skinnemoen static void atmci_queue_request(struct atmel_mci *host, 1322965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot, struct mmc_request *mrq) 1323965ebf33SHaavard Skinnemoen { 1324965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 1325965ebf33SHaavard Skinnemoen host->state); 1326965ebf33SHaavard Skinnemoen 1327965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1328965ebf33SHaavard Skinnemoen slot->mrq = mrq; 1329965ebf33SHaavard Skinnemoen if (host->state == STATE_IDLE) { 1330965ebf33SHaavard Skinnemoen host->state = STATE_SENDING_CMD; 1331965ebf33SHaavard Skinnemoen atmci_start_request(host, slot); 1332965ebf33SHaavard Skinnemoen } else { 13336801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "queue request\n"); 1334965ebf33SHaavard Skinnemoen list_add_tail(&slot->queue_node, &host->queue); 1335965ebf33SHaavard Skinnemoen } 1336965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1337965ebf33SHaavard Skinnemoen } 1338965ebf33SHaavard Skinnemoen 1339965ebf33SHaavard Skinnemoen static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1340965ebf33SHaavard Skinnemoen { 1341965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1342965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1343965ebf33SHaavard Skinnemoen struct mmc_data *data; 1344965ebf33SHaavard Skinnemoen 1345965ebf33SHaavard Skinnemoen WARN_ON(slot->mrq); 13466801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); 1347965ebf33SHaavard Skinnemoen 1348965ebf33SHaavard Skinnemoen /* 1349965ebf33SHaavard Skinnemoen * We may "know" the card is gone even though there's still an 1350965ebf33SHaavard Skinnemoen * electrical connection. If so, we really need to communicate 1351965ebf33SHaavard Skinnemoen * this to the MMC core since there won't be any more 1352965ebf33SHaavard Skinnemoen * interrupts as the card is completely removed. Otherwise, 1353965ebf33SHaavard Skinnemoen * the MMC core might believe the card is still there even 1354965ebf33SHaavard Skinnemoen * though the card was just removed very slowly. 1355965ebf33SHaavard Skinnemoen */ 1356965ebf33SHaavard Skinnemoen if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) { 1357965ebf33SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1358965ebf33SHaavard Skinnemoen mmc_request_done(mmc, mrq); 13597d2be074SHaavard Skinnemoen return; 1360965ebf33SHaavard Skinnemoen } 13617d2be074SHaavard Skinnemoen 1362965ebf33SHaavard Skinnemoen /* We don't support multiple blocks of weird lengths. */ 1363965ebf33SHaavard Skinnemoen data = mrq->data; 1364965ebf33SHaavard Skinnemoen if (data && data->blocks > 1 && data->blksz & 3) { 13657d2be074SHaavard Skinnemoen mrq->cmd->error = -EINVAL; 13667d2be074SHaavard Skinnemoen mmc_request_done(mmc, mrq); 13677d2be074SHaavard Skinnemoen } 13687d2be074SHaavard Skinnemoen 1369965ebf33SHaavard Skinnemoen atmci_queue_request(host, slot, mrq); 1370965ebf33SHaavard Skinnemoen } 1371965ebf33SHaavard Skinnemoen 13727d2be074SHaavard Skinnemoen static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 13737d2be074SHaavard Skinnemoen { 1374965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1375965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1376965ebf33SHaavard Skinnemoen unsigned int i; 1377ae552ab0SWenyou Yang 13782c96a293SLudovic Desroches slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; 1379945533b5SHaavard Skinnemoen switch (ios->bus_width) { 1380945533b5SHaavard Skinnemoen case MMC_BUS_WIDTH_1: 13812c96a293SLudovic Desroches slot->sdc_reg |= ATMCI_SDCBUS_1BIT; 1382945533b5SHaavard Skinnemoen break; 1383945533b5SHaavard Skinnemoen case MMC_BUS_WIDTH_4: 13842c96a293SLudovic Desroches slot->sdc_reg |= ATMCI_SDCBUS_4BIT; 1385945533b5SHaavard Skinnemoen break; 1386b1d14045SNicolas Ferre case MMC_BUS_WIDTH_8: 1387b1d14045SNicolas Ferre slot->sdc_reg |= ATMCI_SDCBUS_8BIT; 1388b1d14045SNicolas Ferre break; 1389945533b5SHaavard Skinnemoen } 1390945533b5SHaavard Skinnemoen 13917d2be074SHaavard Skinnemoen if (ios->clock) { 1392965ebf33SHaavard Skinnemoen unsigned int clock_min = ~0U; 139360c8f783SLudovic Desroches int clkdiv; 13947d2be074SHaavard Skinnemoen 1395965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1396965ebf33SHaavard Skinnemoen if (!host->mode_reg) { 139703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 139803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 1399796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 140003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 1401965ebf33SHaavard Skinnemoen } 1402945533b5SHaavard Skinnemoen 1403965ebf33SHaavard Skinnemoen /* 1404965ebf33SHaavard Skinnemoen * Use mirror of ios->clock to prevent race with mmc 1405965ebf33SHaavard Skinnemoen * core ios update when finding the minimum. 1406965ebf33SHaavard Skinnemoen */ 1407965ebf33SHaavard Skinnemoen slot->clock = ios->clock; 14082c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 1409965ebf33SHaavard Skinnemoen if (host->slot[i] && host->slot[i]->clock 1410965ebf33SHaavard Skinnemoen && host->slot[i]->clock < clock_min) 1411965ebf33SHaavard Skinnemoen clock_min = host->slot[i]->clock; 1412965ebf33SHaavard Skinnemoen } 1413965ebf33SHaavard Skinnemoen 1414965ebf33SHaavard Skinnemoen /* Calculate clock divider */ 1415faf8180bSLudovic Desroches if (host->caps.has_odd_clk_div) { 1416faf8180bSLudovic Desroches clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; 141760c8f783SLudovic Desroches if (clkdiv < 0) { 141860c8f783SLudovic Desroches dev_warn(&mmc->class_dev, 141960c8f783SLudovic Desroches "clock %u too fast; using %lu\n", 142060c8f783SLudovic Desroches clock_min, host->bus_hz / 2); 142160c8f783SLudovic Desroches clkdiv = 0; 142260c8f783SLudovic Desroches } else if (clkdiv > 511) { 1423faf8180bSLudovic Desroches dev_warn(&mmc->class_dev, 1424faf8180bSLudovic Desroches "clock %u too slow; using %lu\n", 1425faf8180bSLudovic Desroches clock_min, host->bus_hz / (511 + 2)); 1426faf8180bSLudovic Desroches clkdiv = 511; 1427faf8180bSLudovic Desroches } 1428faf8180bSLudovic Desroches host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) 1429faf8180bSLudovic Desroches | ATMCI_MR_CLKODD(clkdiv & 1); 1430faf8180bSLudovic Desroches } else { 1431965ebf33SHaavard Skinnemoen clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; 14327d2be074SHaavard Skinnemoen if (clkdiv > 255) { 14337d2be074SHaavard Skinnemoen dev_warn(&mmc->class_dev, 14347d2be074SHaavard Skinnemoen "clock %u too slow; using %lu\n", 1435965ebf33SHaavard Skinnemoen clock_min, host->bus_hz / (2 * 256)); 14367d2be074SHaavard Skinnemoen clkdiv = 255; 14377d2be074SHaavard Skinnemoen } 14382c96a293SLudovic Desroches host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); 1439faf8180bSLudovic Desroches } 144004d699c3SRob Emanuele 1441965ebf33SHaavard Skinnemoen /* 1442965ebf33SHaavard Skinnemoen * WRPROOF and RDPROOF prevent overruns/underruns by 1443965ebf33SHaavard Skinnemoen * stopping the clock when the FIFO is full/empty. 1444965ebf33SHaavard Skinnemoen * This state is not expected to last for long. 1445965ebf33SHaavard Skinnemoen */ 1446796211b7SLudovic Desroches if (host->caps.has_rwproof) 14472c96a293SLudovic Desroches host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); 14487d2be074SHaavard Skinnemoen 1449796211b7SLudovic Desroches if (host->caps.has_cfg_reg) { 145099ddffd8SNicolas Ferre /* setup High Speed mode in relation with card capacity */ 145199ddffd8SNicolas Ferre if (ios->timing == MMC_TIMING_SD_HS) 14522c96a293SLudovic Desroches host->cfg_reg |= ATMCI_CFG_HSMODE; 1453965ebf33SHaavard Skinnemoen else 14542c96a293SLudovic Desroches host->cfg_reg &= ~ATMCI_CFG_HSMODE; 145599ddffd8SNicolas Ferre } 145699ddffd8SNicolas Ferre 145799ddffd8SNicolas Ferre if (list_empty(&host->queue)) { 145803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1459796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 146003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 146199ddffd8SNicolas Ferre } else { 1462965ebf33SHaavard Skinnemoen host->need_clock_update = true; 146399ddffd8SNicolas Ferre } 1464965ebf33SHaavard Skinnemoen 1465965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1466945533b5SHaavard Skinnemoen } else { 1467965ebf33SHaavard Skinnemoen bool any_slot_active = false; 1468965ebf33SHaavard Skinnemoen 1469965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1470965ebf33SHaavard Skinnemoen slot->clock = 0; 14712c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 1472965ebf33SHaavard Skinnemoen if (host->slot[i] && host->slot[i]->clock) { 1473965ebf33SHaavard Skinnemoen any_slot_active = true; 1474965ebf33SHaavard Skinnemoen break; 1475965ebf33SHaavard Skinnemoen } 1476965ebf33SHaavard Skinnemoen } 1477965ebf33SHaavard Skinnemoen if (!any_slot_active) { 147803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); 1479945533b5SHaavard Skinnemoen if (host->mode_reg) { 148003fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_MR); 1481945533b5SHaavard Skinnemoen } 1482945533b5SHaavard Skinnemoen host->mode_reg = 0; 14837d2be074SHaavard Skinnemoen } 1484965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1485965ebf33SHaavard Skinnemoen } 14867d2be074SHaavard Skinnemoen 14877d2be074SHaavard Skinnemoen switch (ios->power_mode) { 14889e7861f5SAlexandre Belloni case MMC_POWER_OFF: 14899e7861f5SAlexandre Belloni if (!IS_ERR(mmc->supply.vmmc)) 14909e7861f5SAlexandre Belloni mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 14919e7861f5SAlexandre Belloni break; 1492965ebf33SHaavard Skinnemoen case MMC_POWER_UP: 1493965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_NEED_INIT, &slot->flags); 14949e7861f5SAlexandre Belloni if (!IS_ERR(mmc->supply.vmmc)) 14959e7861f5SAlexandre Belloni mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); 1496965ebf33SHaavard Skinnemoen break; 14977d2be074SHaavard Skinnemoen default: 14987d2be074SHaavard Skinnemoen break; 14997d2be074SHaavard Skinnemoen } 15007d2be074SHaavard Skinnemoen } 15017d2be074SHaavard Skinnemoen 15027d2be074SHaavard Skinnemoen static int atmci_get_ro(struct mmc_host *mmc) 15037d2be074SHaavard Skinnemoen { 1504965ebf33SHaavard Skinnemoen int read_only = -ENOSYS; 1505965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 15067d2be074SHaavard Skinnemoen 1507965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->wp_pin)) { 1508965ebf33SHaavard Skinnemoen read_only = gpio_get_value(slot->wp_pin); 15097d2be074SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "card is %s\n", 15107d2be074SHaavard Skinnemoen read_only ? "read-only" : "read-write"); 15117d2be074SHaavard Skinnemoen } 15127d2be074SHaavard Skinnemoen 15137d2be074SHaavard Skinnemoen return read_only; 15147d2be074SHaavard Skinnemoen } 15157d2be074SHaavard Skinnemoen 1516965ebf33SHaavard Skinnemoen static int atmci_get_cd(struct mmc_host *mmc) 1517965ebf33SHaavard Skinnemoen { 1518965ebf33SHaavard Skinnemoen int present = -ENOSYS; 1519965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1520965ebf33SHaavard Skinnemoen 1521965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 15221c1452beSJonas Larsson present = !(gpio_get_value(slot->detect_pin) ^ 15231c1452beSJonas Larsson slot->detect_is_active_high); 1524965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "card is %spresent\n", 1525965ebf33SHaavard Skinnemoen present ? "" : "not "); 1526965ebf33SHaavard Skinnemoen } 1527965ebf33SHaavard Skinnemoen 1528965ebf33SHaavard Skinnemoen return present; 1529965ebf33SHaavard Skinnemoen } 1530965ebf33SHaavard Skinnemoen 153188ff82edSAnders Grahn static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) 153288ff82edSAnders Grahn { 153388ff82edSAnders Grahn struct atmel_mci_slot *slot = mmc_priv(mmc); 153488ff82edSAnders Grahn struct atmel_mci *host = slot->host; 153588ff82edSAnders Grahn 153688ff82edSAnders Grahn if (enable) 153703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, slot->sdio_irq); 153888ff82edSAnders Grahn else 153903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, slot->sdio_irq); 154088ff82edSAnders Grahn } 154188ff82edSAnders Grahn 1542965ebf33SHaavard Skinnemoen static const struct mmc_host_ops atmci_ops = { 15437d2be074SHaavard Skinnemoen .request = atmci_request, 15447d2be074SHaavard Skinnemoen .set_ios = atmci_set_ios, 15457d2be074SHaavard Skinnemoen .get_ro = atmci_get_ro, 1546965ebf33SHaavard Skinnemoen .get_cd = atmci_get_cd, 154788ff82edSAnders Grahn .enable_sdio_irq = atmci_enable_sdio_irq, 15487d2be074SHaavard Skinnemoen }; 15497d2be074SHaavard Skinnemoen 1550965ebf33SHaavard Skinnemoen /* Called with host->lock held */ 1551965ebf33SHaavard Skinnemoen static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) 1552965ebf33SHaavard Skinnemoen __releases(&host->lock) 1553965ebf33SHaavard Skinnemoen __acquires(&host->lock) 1554965ebf33SHaavard Skinnemoen { 1555965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = NULL; 1556965ebf33SHaavard Skinnemoen struct mmc_host *prev_mmc = host->cur_slot->mmc; 1557965ebf33SHaavard Skinnemoen 1558965ebf33SHaavard Skinnemoen WARN_ON(host->cmd || host->data); 1559965ebf33SHaavard Skinnemoen 1560965ebf33SHaavard Skinnemoen /* 1561965ebf33SHaavard Skinnemoen * Update the MMC clock rate if necessary. This may be 1562965ebf33SHaavard Skinnemoen * necessary if set_ios() is called when a different slot is 156325985edcSLucas De Marchi * busy transferring data. 1564965ebf33SHaavard Skinnemoen */ 156599ddffd8SNicolas Ferre if (host->need_clock_update) { 156603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1567796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 156803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 156999ddffd8SNicolas Ferre } 1570965ebf33SHaavard Skinnemoen 1571965ebf33SHaavard Skinnemoen host->cur_slot->mrq = NULL; 1572965ebf33SHaavard Skinnemoen host->mrq = NULL; 1573965ebf33SHaavard Skinnemoen if (!list_empty(&host->queue)) { 1574965ebf33SHaavard Skinnemoen slot = list_entry(host->queue.next, 1575965ebf33SHaavard Skinnemoen struct atmel_mci_slot, queue_node); 1576965ebf33SHaavard Skinnemoen list_del(&slot->queue_node); 1577965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", 1578965ebf33SHaavard Skinnemoen mmc_hostname(slot->mmc)); 1579965ebf33SHaavard Skinnemoen host->state = STATE_SENDING_CMD; 1580965ebf33SHaavard Skinnemoen atmci_start_request(host, slot); 1581965ebf33SHaavard Skinnemoen } else { 1582965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "list empty\n"); 1583965ebf33SHaavard Skinnemoen host->state = STATE_IDLE; 1584965ebf33SHaavard Skinnemoen } 1585965ebf33SHaavard Skinnemoen 158624011f34SLudovic Desroches del_timer(&host->timer); 158724011f34SLudovic Desroches 1588965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1589965ebf33SHaavard Skinnemoen mmc_request_done(prev_mmc, mrq); 1590965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1591965ebf33SHaavard Skinnemoen } 1592965ebf33SHaavard Skinnemoen 15937d2be074SHaavard Skinnemoen static void atmci_command_complete(struct atmel_mci *host, 1594c06ad258SHaavard Skinnemoen struct mmc_command *cmd) 15957d2be074SHaavard Skinnemoen { 1596c06ad258SHaavard Skinnemoen u32 status = host->cmd_status; 1597c06ad258SHaavard Skinnemoen 15987d2be074SHaavard Skinnemoen /* Read the response from the card (up to 16 bytes) */ 159903fc9a7fSLudovic Desroches cmd->resp[0] = atmci_readl(host, ATMCI_RSPR); 160003fc9a7fSLudovic Desroches cmd->resp[1] = atmci_readl(host, ATMCI_RSPR); 160103fc9a7fSLudovic Desroches cmd->resp[2] = atmci_readl(host, ATMCI_RSPR); 160203fc9a7fSLudovic Desroches cmd->resp[3] = atmci_readl(host, ATMCI_RSPR); 16037d2be074SHaavard Skinnemoen 16042c96a293SLudovic Desroches if (status & ATMCI_RTOE) 16057d2be074SHaavard Skinnemoen cmd->error = -ETIMEDOUT; 16062c96a293SLudovic Desroches else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE)) 16077d2be074SHaavard Skinnemoen cmd->error = -EILSEQ; 16082c96a293SLudovic Desroches else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) 16097d2be074SHaavard Skinnemoen cmd->error = -EIO; 161024011f34SLudovic Desroches else if (host->mrq->data && (host->mrq->data->blksz & 3)) { 161124011f34SLudovic Desroches if (host->caps.need_blksz_mul_4) { 161224011f34SLudovic Desroches cmd->error = -EINVAL; 161324011f34SLudovic Desroches host->need_reset = 1; 161424011f34SLudovic Desroches } 161524011f34SLudovic Desroches } else 16167d2be074SHaavard Skinnemoen cmd->error = 0; 16177d2be074SHaavard Skinnemoen } 16187d2be074SHaavard Skinnemoen 16192ee4f620SKees Cook static void atmci_detect_change(struct timer_list *t) 16207d2be074SHaavard Skinnemoen { 16212ee4f620SKees Cook struct atmel_mci_slot *slot = from_timer(slot, t, detect_timer); 1622965ebf33SHaavard Skinnemoen bool present; 1623965ebf33SHaavard Skinnemoen bool present_old; 16247d2be074SHaavard Skinnemoen 16257d2be074SHaavard Skinnemoen /* 1626965ebf33SHaavard Skinnemoen * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before 1627965ebf33SHaavard Skinnemoen * freeing the interrupt. We must not re-enable the interrupt 1628965ebf33SHaavard Skinnemoen * if it has been freed, and if we're shutting down, it 1629965ebf33SHaavard Skinnemoen * doesn't really matter whether the card is present or not. 16307d2be074SHaavard Skinnemoen */ 16317d2be074SHaavard Skinnemoen smp_rmb(); 1632965ebf33SHaavard Skinnemoen if (test_bit(ATMCI_SHUTDOWN, &slot->flags)) 16337d2be074SHaavard Skinnemoen return; 16347d2be074SHaavard Skinnemoen 1635965ebf33SHaavard Skinnemoen enable_irq(gpio_to_irq(slot->detect_pin)); 16361c1452beSJonas Larsson present = !(gpio_get_value(slot->detect_pin) ^ 16371c1452beSJonas Larsson slot->detect_is_active_high); 1638965ebf33SHaavard Skinnemoen present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags); 16397d2be074SHaavard Skinnemoen 1640965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n", 1641965ebf33SHaavard Skinnemoen present, present_old); 16427d2be074SHaavard Skinnemoen 1643965ebf33SHaavard Skinnemoen if (present != present_old) { 1644965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1645965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 1646965ebf33SHaavard Skinnemoen 1647965ebf33SHaavard Skinnemoen dev_dbg(&slot->mmc->class_dev, "card %s\n", 16487d2be074SHaavard Skinnemoen present ? "inserted" : "removed"); 16497d2be074SHaavard Skinnemoen 1650965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1651965ebf33SHaavard Skinnemoen 1652965ebf33SHaavard Skinnemoen if (!present) 1653965ebf33SHaavard Skinnemoen clear_bit(ATMCI_CARD_PRESENT, &slot->flags); 1654965ebf33SHaavard Skinnemoen else 1655965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_PRESENT, &slot->flags); 16567d2be074SHaavard Skinnemoen 16577d2be074SHaavard Skinnemoen /* Clean up queue if present */ 1658965ebf33SHaavard Skinnemoen mrq = slot->mrq; 16597d2be074SHaavard Skinnemoen if (mrq) { 1660965ebf33SHaavard Skinnemoen if (mrq == host->mrq) { 16617d2be074SHaavard Skinnemoen /* 16627d2be074SHaavard Skinnemoen * Reset controller to terminate any ongoing 16637d2be074SHaavard Skinnemoen * commands or data transfers. 16647d2be074SHaavard Skinnemoen */ 166503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 166603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 166703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1668796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 166903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 16707d2be074SHaavard Skinnemoen 16717d2be074SHaavard Skinnemoen host->data = NULL; 16727d2be074SHaavard Skinnemoen host->cmd = NULL; 1673c06ad258SHaavard Skinnemoen 1674c06ad258SHaavard Skinnemoen switch (host->state) { 1675965ebf33SHaavard Skinnemoen case STATE_IDLE: 1676965ebf33SHaavard Skinnemoen break; 1677c06ad258SHaavard Skinnemoen case STATE_SENDING_CMD: 1678c06ad258SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1679f5177547SLudovic Desroches if (mrq->data) 1680f5177547SLudovic Desroches host->stop_transfer(host); 1681c06ad258SHaavard Skinnemoen break; 1682f5177547SLudovic Desroches case STATE_DATA_XFER: 1683c06ad258SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1684796211b7SLudovic Desroches host->stop_transfer(host); 1685c06ad258SHaavard Skinnemoen break; 1686f5177547SLudovic Desroches case STATE_WAITING_NOTBUSY: 1687c06ad258SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1688c06ad258SHaavard Skinnemoen break; 1689c06ad258SHaavard Skinnemoen case STATE_SENDING_STOP: 1690c06ad258SHaavard Skinnemoen mrq->stop->error = -ENOMEDIUM; 1691c06ad258SHaavard Skinnemoen break; 1692f5177547SLudovic Desroches case STATE_END_REQUEST: 1693f5177547SLudovic Desroches break; 1694c06ad258SHaavard Skinnemoen } 1695c06ad258SHaavard Skinnemoen 1696965ebf33SHaavard Skinnemoen atmci_request_end(host, mrq); 1697965ebf33SHaavard Skinnemoen } else { 1698965ebf33SHaavard Skinnemoen list_del(&slot->queue_node); 1699965ebf33SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1700965ebf33SHaavard Skinnemoen if (mrq->data) 1701965ebf33SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1702965ebf33SHaavard Skinnemoen if (mrq->stop) 1703965ebf33SHaavard Skinnemoen mrq->stop->error = -ENOMEDIUM; 17047d2be074SHaavard Skinnemoen 1705965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1706965ebf33SHaavard Skinnemoen mmc_request_done(slot->mmc, mrq); 1707965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1708965ebf33SHaavard Skinnemoen } 1709965ebf33SHaavard Skinnemoen } 1710965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1711965ebf33SHaavard Skinnemoen 1712965ebf33SHaavard Skinnemoen mmc_detect_change(slot->mmc, 0); 17137d2be074SHaavard Skinnemoen } 17147d2be074SHaavard Skinnemoen } 17157d2be074SHaavard Skinnemoen 17167d2be074SHaavard Skinnemoen static void atmci_tasklet_func(unsigned long priv) 17177d2be074SHaavard Skinnemoen { 1718965ebf33SHaavard Skinnemoen struct atmel_mci *host = (struct atmel_mci *)priv; 17197d2be074SHaavard Skinnemoen struct mmc_request *mrq = host->mrq; 17207d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 1721c06ad258SHaavard Skinnemoen enum atmel_mci_state state = host->state; 1722c06ad258SHaavard Skinnemoen enum atmel_mci_state prev_state; 1723c06ad258SHaavard Skinnemoen u32 status; 1724c06ad258SHaavard Skinnemoen 1725965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1726965ebf33SHaavard Skinnemoen 1727c06ad258SHaavard Skinnemoen state = host->state; 17287d2be074SHaavard Skinnemoen 1729965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, 1730c06ad258SHaavard Skinnemoen "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", 1731c06ad258SHaavard Skinnemoen state, host->pending_events, host->completed_events, 173203fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_IMR)); 17337d2be074SHaavard Skinnemoen 1734c06ad258SHaavard Skinnemoen do { 1735c06ad258SHaavard Skinnemoen prev_state = state; 17366801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state); 1737c06ad258SHaavard Skinnemoen 1738c06ad258SHaavard Skinnemoen switch (state) { 1739965ebf33SHaavard Skinnemoen case STATE_IDLE: 1740965ebf33SHaavard Skinnemoen break; 1741965ebf33SHaavard Skinnemoen 1742c06ad258SHaavard Skinnemoen case STATE_SENDING_CMD: 1743f5177547SLudovic Desroches /* 1744f5177547SLudovic Desroches * Command has been sent, we are waiting for command 1745f5177547SLudovic Desroches * ready. Then we have three next states possible: 1746f5177547SLudovic Desroches * END_REQUEST by default, WAITING_NOTBUSY if it's a 1747f5177547SLudovic Desroches * command needing it or DATA_XFER if there is data. 1748f5177547SLudovic Desroches */ 17496801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); 1750c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1751f5177547SLudovic Desroches EVENT_CMD_RDY)) 1752c06ad258SHaavard Skinnemoen break; 1753c06ad258SHaavard Skinnemoen 17546801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed cmd ready\n"); 17557d2be074SHaavard Skinnemoen host->cmd = NULL; 1756f5177547SLudovic Desroches atmci_set_completed(host, EVENT_CMD_RDY); 1757c06ad258SHaavard Skinnemoen atmci_command_complete(host, mrq->cmd); 1758f5177547SLudovic Desroches if (mrq->data) { 17596801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 17606801c41aSLudovic Desroches "command with data transfer"); 1761f5177547SLudovic Desroches /* 1762f5177547SLudovic Desroches * If there is a command error don't start 1763f5177547SLudovic Desroches * data transfer. 1764f5177547SLudovic Desroches */ 1765f5177547SLudovic Desroches if (mrq->cmd->error) { 1766f5177547SLudovic Desroches host->stop_transfer(host); 1767f5177547SLudovic Desroches host->data = NULL; 1768f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, 1769f5177547SLudovic Desroches ATMCI_TXRDY | ATMCI_RXRDY 1770f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1771f5177547SLudovic Desroches state = STATE_END_REQUEST; 1772f5177547SLudovic Desroches } else 1773f5177547SLudovic Desroches state = STATE_DATA_XFER; 1774f5177547SLudovic Desroches } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { 17756801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 17766801c41aSLudovic Desroches "command response need waiting notbusy"); 1777f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1778f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1779f5177547SLudovic Desroches } else 1780f5177547SLudovic Desroches state = STATE_END_REQUEST; 1781c06ad258SHaavard Skinnemoen 1782f5177547SLudovic Desroches break; 1783c06ad258SHaavard Skinnemoen 1784f5177547SLudovic Desroches case STATE_DATA_XFER: 1785c06ad258SHaavard Skinnemoen if (atmci_test_and_clear_pending(host, 1786c06ad258SHaavard Skinnemoen EVENT_DATA_ERROR)) { 17876801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed data error\n"); 1788f5177547SLudovic Desroches atmci_set_completed(host, EVENT_DATA_ERROR); 1789f5177547SLudovic Desroches state = STATE_END_REQUEST; 1790c06ad258SHaavard Skinnemoen break; 17917d2be074SHaavard Skinnemoen } 17927d2be074SHaavard Skinnemoen 1793f5177547SLudovic Desroches /* 1794f5177547SLudovic Desroches * A data transfer is in progress. The event expected 1795f5177547SLudovic Desroches * to move to the next state depends of data transfer 1796f5177547SLudovic Desroches * type (PDC or DMA). Once transfer done we can move 1797f5177547SLudovic Desroches * to the next step which is WAITING_NOTBUSY in write 1798f5177547SLudovic Desroches * case and directly SENDING_STOP in read case. 1799f5177547SLudovic Desroches */ 18006801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n"); 1801c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1802c06ad258SHaavard Skinnemoen EVENT_XFER_COMPLETE)) 1803c06ad258SHaavard Skinnemoen break; 18047d2be074SHaavard Skinnemoen 18056801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 18066801c41aSLudovic Desroches "(%s) set completed xfer complete\n", 18076801c41aSLudovic Desroches __func__); 1808c06ad258SHaavard Skinnemoen atmci_set_completed(host, EVENT_XFER_COMPLETE); 1809c06ad258SHaavard Skinnemoen 1810077d4073SLudovic Desroches if (host->caps.need_notbusy_for_read_ops || 1811077d4073SLudovic Desroches (host->data->flags & MMC_DATA_WRITE)) { 1812f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1813f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1814f5177547SLudovic Desroches } else if (host->mrq->stop) { 1815f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); 1816f5177547SLudovic Desroches atmci_send_stop_cmd(host, data); 1817f5177547SLudovic Desroches state = STATE_SENDING_STOP; 1818f5177547SLudovic Desroches } else { 1819c06ad258SHaavard Skinnemoen host->data = NULL; 18207d2be074SHaavard Skinnemoen data->bytes_xfered = data->blocks * data->blksz; 18217d2be074SHaavard Skinnemoen data->error = 0; 1822f5177547SLudovic Desroches state = STATE_END_REQUEST; 18237d2be074SHaavard Skinnemoen } 1824f5177547SLudovic Desroches break; 18257d2be074SHaavard Skinnemoen 1826f5177547SLudovic Desroches case STATE_WAITING_NOTBUSY: 1827f5177547SLudovic Desroches /* 1828f5177547SLudovic Desroches * We can be in the state for two reasons: a command 1829f5177547SLudovic Desroches * requiring waiting not busy signal (stop command 1830f5177547SLudovic Desroches * included) or a write operation. In the latest case, 1831f5177547SLudovic Desroches * we need to send a stop command. 1832f5177547SLudovic Desroches */ 18336801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: not busy?\n"); 1834f5177547SLudovic Desroches if (!atmci_test_and_clear_pending(host, 1835f5177547SLudovic Desroches EVENT_NOTBUSY)) 1836f5177547SLudovic Desroches break; 18377d2be074SHaavard Skinnemoen 18386801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed not busy\n"); 1839f5177547SLudovic Desroches atmci_set_completed(host, EVENT_NOTBUSY); 1840f5177547SLudovic Desroches 1841f5177547SLudovic Desroches if (host->data) { 1842f5177547SLudovic Desroches /* 1843f5177547SLudovic Desroches * For some commands such as CMD53, even if 1844f5177547SLudovic Desroches * there is data transfer, there is no stop 1845f5177547SLudovic Desroches * command to send. 1846f5177547SLudovic Desroches */ 1847f5177547SLudovic Desroches if (host->mrq->stop) { 1848f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, 1849f5177547SLudovic Desroches ATMCI_CMDRDY); 18502c96a293SLudovic Desroches atmci_send_stop_cmd(host, data); 1851f5177547SLudovic Desroches state = STATE_SENDING_STOP; 1852f5177547SLudovic Desroches } else { 1853f5177547SLudovic Desroches host->data = NULL; 1854f5177547SLudovic Desroches data->bytes_xfered = data->blocks 1855f5177547SLudovic Desroches * data->blksz; 1856f5177547SLudovic Desroches data->error = 0; 1857f5177547SLudovic Desroches state = STATE_END_REQUEST; 1858f5177547SLudovic Desroches } 1859f5177547SLudovic Desroches } else 1860f5177547SLudovic Desroches state = STATE_END_REQUEST; 1861f5177547SLudovic Desroches break; 1862c06ad258SHaavard Skinnemoen 1863c06ad258SHaavard Skinnemoen case STATE_SENDING_STOP: 1864f5177547SLudovic Desroches /* 1865f5177547SLudovic Desroches * In this state, it is important to set host->data to 1866f5177547SLudovic Desroches * NULL (which is tested in the waiting notbusy state) 1867f5177547SLudovic Desroches * in order to go to the end request state instead of 1868f5177547SLudovic Desroches * sending stop again. 1869f5177547SLudovic Desroches */ 18706801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); 1871c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1872f5177547SLudovic Desroches EVENT_CMD_RDY)) 1873c06ad258SHaavard Skinnemoen break; 1874c06ad258SHaavard Skinnemoen 18756801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); 1876c06ad258SHaavard Skinnemoen host->cmd = NULL; 1877f5177547SLudovic Desroches data->bytes_xfered = data->blocks * data->blksz; 1878f5177547SLudovic Desroches data->error = 0; 1879c06ad258SHaavard Skinnemoen atmci_command_complete(host, mrq->stop); 1880f5177547SLudovic Desroches if (mrq->stop->error) { 1881f5177547SLudovic Desroches host->stop_transfer(host); 1882f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, 1883f5177547SLudovic Desroches ATMCI_TXRDY | ATMCI_RXRDY 1884f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1885f5177547SLudovic Desroches state = STATE_END_REQUEST; 1886f5177547SLudovic Desroches } else { 1887f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1888f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1889f5177547SLudovic Desroches } 189041b4e9a1SNicolas Ferre host->data = NULL; 1891c06ad258SHaavard Skinnemoen break; 1892c06ad258SHaavard Skinnemoen 1893f5177547SLudovic Desroches case STATE_END_REQUEST: 1894f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY 1895f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1896f5177547SLudovic Desroches status = host->data_status; 1897f5177547SLudovic Desroches if (unlikely(status)) { 1898f5177547SLudovic Desroches host->stop_transfer(host); 1899f5177547SLudovic Desroches host->data = NULL; 1900fbd986cdSRodolfo Giometti if (data) { 1901f5177547SLudovic Desroches if (status & ATMCI_DTOE) { 1902f5177547SLudovic Desroches data->error = -ETIMEDOUT; 1903f5177547SLudovic Desroches } else if (status & ATMCI_DCRCE) { 1904f5177547SLudovic Desroches data->error = -EILSEQ; 1905f5177547SLudovic Desroches } else { 1906f5177547SLudovic Desroches data->error = -EIO; 1907f5177547SLudovic Desroches } 1908f5177547SLudovic Desroches } 1909fbd986cdSRodolfo Giometti } 1910f5177547SLudovic Desroches 1911f5177547SLudovic Desroches atmci_request_end(host, host->mrq); 1912ae460c11SJonas Danielsson goto unlock; /* atmci_request_end() sets host->state */ 1913c06ad258SHaavard Skinnemoen break; 1914c06ad258SHaavard Skinnemoen } 1915c06ad258SHaavard Skinnemoen } while (state != prev_state); 1916c06ad258SHaavard Skinnemoen 1917c06ad258SHaavard Skinnemoen host->state = state; 1918965ebf33SHaavard Skinnemoen 1919ae460c11SJonas Danielsson unlock: 1920965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 19217d2be074SHaavard Skinnemoen } 19227d2be074SHaavard Skinnemoen 19237d2be074SHaavard Skinnemoen static void atmci_read_data_pio(struct atmel_mci *host) 19247d2be074SHaavard Skinnemoen { 19257d2be074SHaavard Skinnemoen struct scatterlist *sg = host->sg; 19267d2be074SHaavard Skinnemoen unsigned int offset = host->pio_offset; 19277d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 19287d2be074SHaavard Skinnemoen u32 value; 19297d2be074SHaavard Skinnemoen u32 status; 19307d2be074SHaavard Skinnemoen unsigned int nbytes = 0; 19317d2be074SHaavard Skinnemoen 19327d2be074SHaavard Skinnemoen do { 193303fc9a7fSLudovic Desroches value = atmci_readl(host, ATMCI_RDR); 19347d2be074SHaavard Skinnemoen if (likely(offset + 4 <= sg->length)) { 193519f5e9e0SLudovic Desroches sg_pcopy_from_buffer(sg, 1, &value, sizeof(u32), offset); 19367d2be074SHaavard Skinnemoen 19377d2be074SHaavard Skinnemoen offset += 4; 19387d2be074SHaavard Skinnemoen nbytes += 4; 19397d2be074SHaavard Skinnemoen 19407d2be074SHaavard Skinnemoen if (offset == sg->length) { 19415e7184aeSHaavard Skinnemoen flush_dcache_page(sg_page(sg)); 19427d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 1943bdbc5d0cSTerry Barnaby host->sg_len--; 1944bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) 19457d2be074SHaavard Skinnemoen goto done; 19467d2be074SHaavard Skinnemoen 19477d2be074SHaavard Skinnemoen offset = 0; 19487d2be074SHaavard Skinnemoen } 19497d2be074SHaavard Skinnemoen } else { 19507d2be074SHaavard Skinnemoen unsigned int remaining = sg->length - offset; 19515b427781SChristoph Hellwig 195219f5e9e0SLudovic Desroches sg_pcopy_from_buffer(sg, 1, &value, remaining, offset); 19537d2be074SHaavard Skinnemoen nbytes += remaining; 19547d2be074SHaavard Skinnemoen 19557d2be074SHaavard Skinnemoen flush_dcache_page(sg_page(sg)); 19567d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 1957bdbc5d0cSTerry Barnaby host->sg_len--; 1958bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) 19597d2be074SHaavard Skinnemoen goto done; 19607d2be074SHaavard Skinnemoen 19617d2be074SHaavard Skinnemoen offset = 4 - remaining; 196219f5e9e0SLudovic Desroches sg_pcopy_from_buffer(sg, 1, (u8 *)&value + remaining, 19635b427781SChristoph Hellwig offset, 0); 19647d2be074SHaavard Skinnemoen nbytes += offset; 19657d2be074SHaavard Skinnemoen } 19667d2be074SHaavard Skinnemoen 196703fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 19687d2be074SHaavard Skinnemoen if (status & ATMCI_DATA_ERROR_FLAGS) { 196903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY 19707d2be074SHaavard Skinnemoen | ATMCI_DATA_ERROR_FLAGS)); 19717d2be074SHaavard Skinnemoen host->data_status = status; 1972965ebf33SHaavard Skinnemoen data->bytes_xfered += nbytes; 1973965ebf33SHaavard Skinnemoen return; 19747d2be074SHaavard Skinnemoen } 19752c96a293SLudovic Desroches } while (status & ATMCI_RXRDY); 19767d2be074SHaavard Skinnemoen 19777d2be074SHaavard Skinnemoen host->pio_offset = offset; 19787d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 19797d2be074SHaavard Skinnemoen 19807d2be074SHaavard Skinnemoen return; 19817d2be074SHaavard Skinnemoen 19827d2be074SHaavard Skinnemoen done: 198303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY); 198403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 19857d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 1986965ebf33SHaavard Skinnemoen smp_wmb(); 1987c06ad258SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 19887d2be074SHaavard Skinnemoen } 19897d2be074SHaavard Skinnemoen 19907d2be074SHaavard Skinnemoen static void atmci_write_data_pio(struct atmel_mci *host) 19917d2be074SHaavard Skinnemoen { 19927d2be074SHaavard Skinnemoen struct scatterlist *sg = host->sg; 19937d2be074SHaavard Skinnemoen unsigned int offset = host->pio_offset; 19947d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 19957d2be074SHaavard Skinnemoen u32 value; 19967d2be074SHaavard Skinnemoen u32 status; 19977d2be074SHaavard Skinnemoen unsigned int nbytes = 0; 19987d2be074SHaavard Skinnemoen 19997d2be074SHaavard Skinnemoen do { 20007d2be074SHaavard Skinnemoen if (likely(offset + 4 <= sg->length)) { 200119f5e9e0SLudovic Desroches sg_pcopy_to_buffer(sg, 1, &value, sizeof(u32), offset); 200203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20037d2be074SHaavard Skinnemoen 20047d2be074SHaavard Skinnemoen offset += 4; 20057d2be074SHaavard Skinnemoen nbytes += 4; 20067d2be074SHaavard Skinnemoen if (offset == sg->length) { 20077d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 2008bdbc5d0cSTerry Barnaby host->sg_len--; 2009bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) 20107d2be074SHaavard Skinnemoen goto done; 20117d2be074SHaavard Skinnemoen 20127d2be074SHaavard Skinnemoen offset = 0; 20137d2be074SHaavard Skinnemoen } 20147d2be074SHaavard Skinnemoen } else { 20157d2be074SHaavard Skinnemoen unsigned int remaining = sg->length - offset; 20167d2be074SHaavard Skinnemoen 20177d2be074SHaavard Skinnemoen value = 0; 201819f5e9e0SLudovic Desroches sg_pcopy_to_buffer(sg, 1, &value, remaining, offset); 20197d2be074SHaavard Skinnemoen nbytes += remaining; 20207d2be074SHaavard Skinnemoen 20217d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 2022bdbc5d0cSTerry Barnaby host->sg_len--; 2023bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) { 202403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20257d2be074SHaavard Skinnemoen goto done; 20267d2be074SHaavard Skinnemoen } 20277d2be074SHaavard Skinnemoen 20287d2be074SHaavard Skinnemoen offset = 4 - remaining; 202919f5e9e0SLudovic Desroches sg_pcopy_to_buffer(sg, 1, (u8 *)&value + remaining, 20305b427781SChristoph Hellwig offset, 0); 203103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20327d2be074SHaavard Skinnemoen nbytes += offset; 20337d2be074SHaavard Skinnemoen } 20347d2be074SHaavard Skinnemoen 203503fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 20367d2be074SHaavard Skinnemoen if (status & ATMCI_DATA_ERROR_FLAGS) { 203703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY 20387d2be074SHaavard Skinnemoen | ATMCI_DATA_ERROR_FLAGS)); 20397d2be074SHaavard Skinnemoen host->data_status = status; 2040965ebf33SHaavard Skinnemoen data->bytes_xfered += nbytes; 2041965ebf33SHaavard Skinnemoen return; 20427d2be074SHaavard Skinnemoen } 20432c96a293SLudovic Desroches } while (status & ATMCI_TXRDY); 20447d2be074SHaavard Skinnemoen 20457d2be074SHaavard Skinnemoen host->pio_offset = offset; 20467d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 20477d2be074SHaavard Skinnemoen 20487d2be074SHaavard Skinnemoen return; 20497d2be074SHaavard Skinnemoen 20507d2be074SHaavard Skinnemoen done: 205103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY); 205203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 20537d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 2054965ebf33SHaavard Skinnemoen smp_wmb(); 2055c06ad258SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 20567d2be074SHaavard Skinnemoen } 20577d2be074SHaavard Skinnemoen 205888ff82edSAnders Grahn static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) 205988ff82edSAnders Grahn { 206088ff82edSAnders Grahn int i; 206188ff82edSAnders Grahn 20622c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 206388ff82edSAnders Grahn struct atmel_mci_slot *slot = host->slot[i]; 206488ff82edSAnders Grahn if (slot && (status & slot->sdio_irq)) { 206588ff82edSAnders Grahn mmc_signal_sdio_irq(slot->mmc); 206688ff82edSAnders Grahn } 206788ff82edSAnders Grahn } 206888ff82edSAnders Grahn } 206988ff82edSAnders Grahn 207088ff82edSAnders Grahn 20717d2be074SHaavard Skinnemoen static irqreturn_t atmci_interrupt(int irq, void *dev_id) 20727d2be074SHaavard Skinnemoen { 2073965ebf33SHaavard Skinnemoen struct atmel_mci *host = dev_id; 20747d2be074SHaavard Skinnemoen u32 status, mask, pending; 20757d2be074SHaavard Skinnemoen unsigned int pass_count = 0; 20767d2be074SHaavard Skinnemoen 20777d2be074SHaavard Skinnemoen do { 207803fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 207903fc9a7fSLudovic Desroches mask = atmci_readl(host, ATMCI_IMR); 20807d2be074SHaavard Skinnemoen pending = status & mask; 20817d2be074SHaavard Skinnemoen if (!pending) 20827d2be074SHaavard Skinnemoen break; 20837d2be074SHaavard Skinnemoen 20847d2be074SHaavard Skinnemoen if (pending & ATMCI_DATA_ERROR_FLAGS) { 20856801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: data error\n"); 208603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS 2087f5177547SLudovic Desroches | ATMCI_RXRDY | ATMCI_TXRDY 2088f5177547SLudovic Desroches | ATMCI_ENDRX | ATMCI_ENDTX 2089f5177547SLudovic Desroches | ATMCI_RXBUFF | ATMCI_TXBUFE); 2090965ebf33SHaavard Skinnemoen 20917d2be074SHaavard Skinnemoen host->data_status = status; 20926801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending data error\n"); 2093965ebf33SHaavard Skinnemoen smp_wmb(); 20947d2be074SHaavard Skinnemoen atmci_set_pending(host, EVENT_DATA_ERROR); 20957d2be074SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 20967d2be074SHaavard Skinnemoen } 2097796211b7SLudovic Desroches 2098796211b7SLudovic Desroches if (pending & ATMCI_TXBUFE) { 20996801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n"); 2100796211b7SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); 21017e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); 2102796211b7SLudovic Desroches /* 2103796211b7SLudovic Desroches * We can receive this interruption before having configured 2104796211b7SLudovic Desroches * the second pdc buffer, so we need to reconfigure first and 2105796211b7SLudovic Desroches * second buffers again 2106796211b7SLudovic Desroches */ 2107796211b7SLudovic Desroches if (host->data_size) { 2108796211b7SLudovic Desroches atmci_pdc_set_both_buf(host, XFER_TRANSMIT); 21097e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); 2110796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); 2111796211b7SLudovic Desroches } else { 2112796211b7SLudovic Desroches atmci_pdc_complete(host); 2113796211b7SLudovic Desroches } 21147e8ba228SLudovic Desroches } else if (pending & ATMCI_ENDTX) { 21156801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n"); 21167e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); 21177e8ba228SLudovic Desroches 21187e8ba228SLudovic Desroches if (host->data_size) { 21197e8ba228SLudovic Desroches atmci_pdc_set_single_buf(host, 21207e8ba228SLudovic Desroches XFER_TRANSMIT, PDC_SECOND_BUF); 21217e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); 21227e8ba228SLudovic Desroches } 2123796211b7SLudovic Desroches } 2124796211b7SLudovic Desroches 21257e8ba228SLudovic Desroches if (pending & ATMCI_RXBUFF) { 21266801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n"); 21277e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); 21287e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); 21297e8ba228SLudovic Desroches /* 21307e8ba228SLudovic Desroches * We can receive this interruption before having configured 21317e8ba228SLudovic Desroches * the second pdc buffer, so we need to reconfigure first and 21327e8ba228SLudovic Desroches * second buffers again 21337e8ba228SLudovic Desroches */ 21347e8ba228SLudovic Desroches if (host->data_size) { 21357e8ba228SLudovic Desroches atmci_pdc_set_both_buf(host, XFER_RECEIVE); 21367e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); 21377e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); 21387e8ba228SLudovic Desroches } else { 21397e8ba228SLudovic Desroches atmci_pdc_complete(host); 21407e8ba228SLudovic Desroches } 21417e8ba228SLudovic Desroches } else if (pending & ATMCI_ENDRX) { 21426801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n"); 2143796211b7SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); 2144796211b7SLudovic Desroches 2145796211b7SLudovic Desroches if (host->data_size) { 2146796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, 2147796211b7SLudovic Desroches XFER_RECEIVE, PDC_SECOND_BUF); 2148796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); 2149796211b7SLudovic Desroches } 2150796211b7SLudovic Desroches } 2151796211b7SLudovic Desroches 2152f5177547SLudovic Desroches /* 2153f5177547SLudovic Desroches * First mci IPs, so mainly the ones having pdc, have some 2154f5177547SLudovic Desroches * issues with the notbusy signal. You can't get it after 2155f5177547SLudovic Desroches * data transmission if you have not sent a stop command. 2156f5177547SLudovic Desroches * The appropriate workaround is to use the BLKE signal. 2157f5177547SLudovic Desroches */ 2158f5177547SLudovic Desroches if (pending & ATMCI_BLKE) { 21596801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: blke\n"); 2160f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_BLKE); 2161965ebf33SHaavard Skinnemoen smp_wmb(); 21626801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending notbusy\n"); 2163f5177547SLudovic Desroches atmci_set_pending(host, EVENT_NOTBUSY); 21647d2be074SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 21657d2be074SHaavard Skinnemoen } 2166f5177547SLudovic Desroches 2167f5177547SLudovic Desroches if (pending & ATMCI_NOTBUSY) { 21686801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); 2169f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); 2170f5177547SLudovic Desroches smp_wmb(); 21716801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending notbusy\n"); 2172f5177547SLudovic Desroches atmci_set_pending(host, EVENT_NOTBUSY); 2173f5177547SLudovic Desroches tasklet_schedule(&host->tasklet); 2174f5177547SLudovic Desroches } 2175f5177547SLudovic Desroches 21762c96a293SLudovic Desroches if (pending & ATMCI_RXRDY) 21777d2be074SHaavard Skinnemoen atmci_read_data_pio(host); 21782c96a293SLudovic Desroches if (pending & ATMCI_TXRDY) 21797d2be074SHaavard Skinnemoen atmci_write_data_pio(host); 21807d2be074SHaavard Skinnemoen 2181f5177547SLudovic Desroches if (pending & ATMCI_CMDRDY) { 21826801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n"); 2183f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); 2184f5177547SLudovic Desroches host->cmd_status = status; 2185f5177547SLudovic Desroches smp_wmb(); 21866801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending cmd rdy\n"); 2187f5177547SLudovic Desroches atmci_set_pending(host, EVENT_CMD_RDY); 2188f5177547SLudovic Desroches tasklet_schedule(&host->tasklet); 2189f5177547SLudovic Desroches } 219088ff82edSAnders Grahn 21912c96a293SLudovic Desroches if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) 219288ff82edSAnders Grahn atmci_sdio_interrupt(host, status); 219388ff82edSAnders Grahn 21947d2be074SHaavard Skinnemoen } while (pass_count++ < 5); 21957d2be074SHaavard Skinnemoen 21967d2be074SHaavard Skinnemoen return pass_count ? IRQ_HANDLED : IRQ_NONE; 21977d2be074SHaavard Skinnemoen } 21987d2be074SHaavard Skinnemoen 21997d2be074SHaavard Skinnemoen static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) 22007d2be074SHaavard Skinnemoen { 2201965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = dev_id; 22027d2be074SHaavard Skinnemoen 22037d2be074SHaavard Skinnemoen /* 22047d2be074SHaavard Skinnemoen * Disable interrupts until the pin has stabilized and check 22057d2be074SHaavard Skinnemoen * the state then. Use mod_timer() since we may be in the 22067d2be074SHaavard Skinnemoen * middle of the timer routine when this interrupt triggers. 22077d2be074SHaavard Skinnemoen */ 22087d2be074SHaavard Skinnemoen disable_irq_nosync(irq); 2209965ebf33SHaavard Skinnemoen mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20)); 22107d2be074SHaavard Skinnemoen 22117d2be074SHaavard Skinnemoen return IRQ_HANDLED; 22127d2be074SHaavard Skinnemoen } 22137d2be074SHaavard Skinnemoen 2214ab050b92Sludovic.desroches@atmel.com static int atmci_init_slot(struct atmel_mci *host, 2215965ebf33SHaavard Skinnemoen struct mci_slot_pdata *slot_data, unsigned int id, 221688ff82edSAnders Grahn u32 sdc_reg, u32 sdio_irq) 2217965ebf33SHaavard Skinnemoen { 2218965ebf33SHaavard Skinnemoen struct mmc_host *mmc; 2219965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot; 2220965ebf33SHaavard Skinnemoen 2221965ebf33SHaavard Skinnemoen mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev); 2222965ebf33SHaavard Skinnemoen if (!mmc) 2223965ebf33SHaavard Skinnemoen return -ENOMEM; 2224965ebf33SHaavard Skinnemoen 2225965ebf33SHaavard Skinnemoen slot = mmc_priv(mmc); 2226965ebf33SHaavard Skinnemoen slot->mmc = mmc; 2227965ebf33SHaavard Skinnemoen slot->host = host; 2228965ebf33SHaavard Skinnemoen slot->detect_pin = slot_data->detect_pin; 2229965ebf33SHaavard Skinnemoen slot->wp_pin = slot_data->wp_pin; 22301c1452beSJonas Larsson slot->detect_is_active_high = slot_data->detect_is_active_high; 2231965ebf33SHaavard Skinnemoen slot->sdc_reg = sdc_reg; 223288ff82edSAnders Grahn slot->sdio_irq = sdio_irq; 2233965ebf33SHaavard Skinnemoen 2234e919fd20SLudovic Desroches dev_dbg(&mmc->class_dev, 2235e919fd20SLudovic Desroches "slot[%u]: bus_width=%u, detect_pin=%d, " 2236e919fd20SLudovic Desroches "detect_is_active_high=%s, wp_pin=%d\n", 2237e919fd20SLudovic Desroches id, slot_data->bus_width, slot_data->detect_pin, 2238e919fd20SLudovic Desroches slot_data->detect_is_active_high ? "true" : "false", 2239e919fd20SLudovic Desroches slot_data->wp_pin); 2240e919fd20SLudovic Desroches 2241965ebf33SHaavard Skinnemoen mmc->ops = &atmci_ops; 2242965ebf33SHaavard Skinnemoen mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); 2243965ebf33SHaavard Skinnemoen mmc->f_max = host->bus_hz / 2; 2244965ebf33SHaavard Skinnemoen mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 224588ff82edSAnders Grahn if (sdio_irq) 224688ff82edSAnders Grahn mmc->caps |= MMC_CAP_SDIO_IRQ; 2247796211b7SLudovic Desroches if (host->caps.has_highspeed) 224899ddffd8SNicolas Ferre mmc->caps |= MMC_CAP_SD_HIGHSPEED; 22497a90dcc2SLudovic Desroches /* 22507a90dcc2SLudovic Desroches * Without the read/write proof capability, it is strongly suggested to 22517a90dcc2SLudovic Desroches * use only one bit for data to prevent fifo underruns and overruns 22527a90dcc2SLudovic Desroches * which will corrupt data. 22537a90dcc2SLudovic Desroches */ 2254b1d14045SNicolas Ferre if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) { 2255965ebf33SHaavard Skinnemoen mmc->caps |= MMC_CAP_4_BIT_DATA; 2256b1d14045SNicolas Ferre if (slot_data->bus_width >= 8) 2257b1d14045SNicolas Ferre mmc->caps |= MMC_CAP_8_BIT_DATA; 2258b1d14045SNicolas Ferre } 2259965ebf33SHaavard Skinnemoen 22607a90dcc2SLudovic Desroches if (atmci_get_version(host) < 0x200) { 22617a90dcc2SLudovic Desroches mmc->max_segs = 256; 22627a90dcc2SLudovic Desroches mmc->max_blk_size = 4095; 22637a90dcc2SLudovic Desroches mmc->max_blk_count = 256; 22647a90dcc2SLudovic Desroches mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 22657a90dcc2SLudovic Desroches mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs; 22667a90dcc2SLudovic Desroches } else { 2267a36274e0SMartin K. Petersen mmc->max_segs = 64; 2268965ebf33SHaavard Skinnemoen mmc->max_req_size = 32768 * 512; 2269965ebf33SHaavard Skinnemoen mmc->max_blk_size = 32768; 2270965ebf33SHaavard Skinnemoen mmc->max_blk_count = 512; 22717a90dcc2SLudovic Desroches } 2272965ebf33SHaavard Skinnemoen 2273965ebf33SHaavard Skinnemoen /* Assume card is present initially */ 2274965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_PRESENT, &slot->flags); 2275965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 22767bca646eSPramod Gurav if (devm_gpio_request(&host->pdev->dev, slot->detect_pin, 22777bca646eSPramod Gurav "mmc_detect")) { 2278965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "no detect pin available\n"); 2279965ebf33SHaavard Skinnemoen slot->detect_pin = -EBUSY; 22801c1452beSJonas Larsson } else if (gpio_get_value(slot->detect_pin) ^ 22811c1452beSJonas Larsson slot->detect_is_active_high) { 2282965ebf33SHaavard Skinnemoen clear_bit(ATMCI_CARD_PRESENT, &slot->flags); 2283965ebf33SHaavard Skinnemoen } 2284965ebf33SHaavard Skinnemoen } 2285965ebf33SHaavard Skinnemoen 228676d55564STimo Kokkonen if (!gpio_is_valid(slot->detect_pin)) { 228776d55564STimo Kokkonen if (slot_data->non_removable) 228876d55564STimo Kokkonen mmc->caps |= MMC_CAP_NONREMOVABLE; 228976d55564STimo Kokkonen else 2290965ebf33SHaavard Skinnemoen mmc->caps |= MMC_CAP_NEEDS_POLL; 229176d55564STimo Kokkonen } 2292965ebf33SHaavard Skinnemoen 2293965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->wp_pin)) { 22947bca646eSPramod Gurav if (devm_gpio_request(&host->pdev->dev, slot->wp_pin, 22957bca646eSPramod Gurav "mmc_wp")) { 2296965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "no WP pin available\n"); 2297965ebf33SHaavard Skinnemoen slot->wp_pin = -EBUSY; 2298965ebf33SHaavard Skinnemoen } 2299965ebf33SHaavard Skinnemoen } 2300965ebf33SHaavard Skinnemoen 2301965ebf33SHaavard Skinnemoen host->slot[id] = slot; 23029e7861f5SAlexandre Belloni mmc_regulator_get_supply(mmc); 2303965ebf33SHaavard Skinnemoen mmc_add_host(mmc); 2304965ebf33SHaavard Skinnemoen 2305965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 2306965ebf33SHaavard Skinnemoen int ret; 2307965ebf33SHaavard Skinnemoen 23082ee4f620SKees Cook timer_setup(&slot->detect_timer, atmci_detect_change, 0); 2309965ebf33SHaavard Skinnemoen 2310965ebf33SHaavard Skinnemoen ret = request_irq(gpio_to_irq(slot->detect_pin), 2311965ebf33SHaavard Skinnemoen atmci_detect_interrupt, 2312965ebf33SHaavard Skinnemoen IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 2313965ebf33SHaavard Skinnemoen "mmc-detect", slot); 2314965ebf33SHaavard Skinnemoen if (ret) { 2315965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, 2316965ebf33SHaavard Skinnemoen "could not request IRQ %d for detect pin\n", 2317965ebf33SHaavard Skinnemoen gpio_to_irq(slot->detect_pin)); 2318965ebf33SHaavard Skinnemoen slot->detect_pin = -EBUSY; 2319965ebf33SHaavard Skinnemoen } 2320965ebf33SHaavard Skinnemoen } 2321965ebf33SHaavard Skinnemoen 2322965ebf33SHaavard Skinnemoen atmci_init_debugfs(slot); 2323965ebf33SHaavard Skinnemoen 2324965ebf33SHaavard Skinnemoen return 0; 2325965ebf33SHaavard Skinnemoen } 2326965ebf33SHaavard Skinnemoen 23275fef365bSArnd Bergmann static void atmci_cleanup_slot(struct atmel_mci_slot *slot, 2328965ebf33SHaavard Skinnemoen unsigned int id) 2329965ebf33SHaavard Skinnemoen { 2330965ebf33SHaavard Skinnemoen /* Debugfs stuff is cleaned up by mmc core */ 2331965ebf33SHaavard Skinnemoen 2332965ebf33SHaavard Skinnemoen set_bit(ATMCI_SHUTDOWN, &slot->flags); 2333965ebf33SHaavard Skinnemoen smp_wmb(); 2334965ebf33SHaavard Skinnemoen 2335965ebf33SHaavard Skinnemoen mmc_remove_host(slot->mmc); 2336965ebf33SHaavard Skinnemoen 2337965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 2338965ebf33SHaavard Skinnemoen int pin = slot->detect_pin; 2339965ebf33SHaavard Skinnemoen 2340965ebf33SHaavard Skinnemoen free_irq(gpio_to_irq(pin), slot); 2341965ebf33SHaavard Skinnemoen del_timer_sync(&slot->detect_timer); 2342965ebf33SHaavard Skinnemoen } 2343965ebf33SHaavard Skinnemoen 2344965ebf33SHaavard Skinnemoen slot->host->slot[id] = NULL; 2345965ebf33SHaavard Skinnemoen mmc_free_host(slot->mmc); 2346965ebf33SHaavard Skinnemoen } 2347965ebf33SHaavard Skinnemoen 2348467e081dSludovic.desroches@atmel.com static int atmci_configure_dma(struct atmel_mci *host) 23492635d1baSNicolas Ferre { 23505503301fSPeter Ujfalusi host->dma.chan = dma_request_chan(&host->pdev->dev, "rxtx"); 235174843787SMans Rullgard 235274843787SMans Rullgard if (PTR_ERR(host->dma.chan) == -ENODEV) { 235374843787SMans Rullgard struct mci_platform_data *pdata = host->pdev->dev.platform_data; 235474843787SMans Rullgard dma_cap_mask_t mask; 235574843787SMans Rullgard 235693c77d29SBrent Taylor if (!pdata || !pdata->dma_filter) 235774843787SMans Rullgard return -ENODEV; 235874843787SMans Rullgard 235974843787SMans Rullgard dma_cap_zero(mask); 236074843787SMans Rullgard dma_cap_set(DMA_SLAVE, mask); 236174843787SMans Rullgard 236274843787SMans Rullgard host->dma.chan = dma_request_channel(mask, pdata->dma_filter, 236374843787SMans Rullgard pdata->dma_slave); 236474843787SMans Rullgard if (!host->dma.chan) 236574843787SMans Rullgard host->dma.chan = ERR_PTR(-ENODEV); 236674843787SMans Rullgard } 236774843787SMans Rullgard 2368467e081dSludovic.desroches@atmel.com if (IS_ERR(host->dma.chan)) 2369467e081dSludovic.desroches@atmel.com return PTR_ERR(host->dma.chan); 23702635d1baSNicolas Ferre 2371467e081dSludovic.desroches@atmel.com dev_info(&host->pdev->dev, "using %s for DMA transfers\n", 237274791a2dSNicolas Ferre dma_chan_name(host->dma.chan)); 2373e2b35f3dSViresh Kumar 2374e2b35f3dSViresh Kumar host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; 2375e2b35f3dSViresh Kumar host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 2376e2b35f3dSViresh Kumar host->dma_conf.src_maxburst = 1; 2377e2b35f3dSViresh Kumar host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; 2378e2b35f3dSViresh Kumar host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 2379e2b35f3dSViresh Kumar host->dma_conf.dst_maxburst = 1; 2380e2b35f3dSViresh Kumar host->dma_conf.device_fc = false; 2381467e081dSludovic.desroches@atmel.com 2382467e081dSludovic.desroches@atmel.com return 0; 23832635d1baSNicolas Ferre } 2384796211b7SLudovic Desroches 2385796211b7SLudovic Desroches /* 2386796211b7SLudovic Desroches * HSMCI (High Speed MCI) module is not fully compatible with MCI module. 2387796211b7SLudovic Desroches * HSMCI provides DMA support and a new config register but no more supports 2388796211b7SLudovic Desroches * PDC. 2389796211b7SLudovic Desroches */ 2390ab050b92Sludovic.desroches@atmel.com static void atmci_get_cap(struct atmel_mci *host) 2391796211b7SLudovic Desroches { 2392796211b7SLudovic Desroches unsigned int version; 2393796211b7SLudovic Desroches 2394796211b7SLudovic Desroches version = atmci_get_version(host); 2395796211b7SLudovic Desroches dev_info(&host->pdev->dev, 2396796211b7SLudovic Desroches "version: 0x%x\n", version); 2397796211b7SLudovic Desroches 2398ccdfe612SHein_Tibosch host->caps.has_dma_conf_reg = 0; 2399ef4b160fSAndy Shevchenko host->caps.has_pdc = 1; 2400796211b7SLudovic Desroches host->caps.has_cfg_reg = 0; 2401796211b7SLudovic Desroches host->caps.has_cstor_reg = 0; 2402796211b7SLudovic Desroches host->caps.has_highspeed = 0; 2403796211b7SLudovic Desroches host->caps.has_rwproof = 0; 2404faf8180bSLudovic Desroches host->caps.has_odd_clk_div = 0; 240524011f34SLudovic Desroches host->caps.has_bad_data_ordering = 1; 240624011f34SLudovic Desroches host->caps.need_reset_after_xfer = 1; 240724011f34SLudovic Desroches host->caps.need_blksz_mul_4 = 1; 2408077d4073SLudovic Desroches host->caps.need_notbusy_for_read_ops = 0; 2409796211b7SLudovic Desroches 2410796211b7SLudovic Desroches /* keep only major version number */ 2411796211b7SLudovic Desroches switch (version & 0xf00) { 2412215ba399SNicolas Ferre case 0x600: 2413796211b7SLudovic Desroches case 0x500: 2414faf8180bSLudovic Desroches host->caps.has_odd_clk_div = 1; 24157789a98aSGustavo A. R. Silva /* Fall through */ 2416faf8180bSLudovic Desroches case 0x400: 2417faf8180bSLudovic Desroches case 0x300: 2418ccdfe612SHein_Tibosch host->caps.has_dma_conf_reg = 1; 2419faf8180bSLudovic Desroches host->caps.has_pdc = 0; 2420796211b7SLudovic Desroches host->caps.has_cfg_reg = 1; 2421796211b7SLudovic Desroches host->caps.has_cstor_reg = 1; 2422796211b7SLudovic Desroches host->caps.has_highspeed = 1; 24237789a98aSGustavo A. R. Silva /* Fall through */ 2424faf8180bSLudovic Desroches case 0x200: 2425796211b7SLudovic Desroches host->caps.has_rwproof = 1; 242624011f34SLudovic Desroches host->caps.need_blksz_mul_4 = 0; 2427077d4073SLudovic Desroches host->caps.need_notbusy_for_read_ops = 1; 24287789a98aSGustavo A. R. Silva /* Fall through */ 2429faf8180bSLudovic Desroches case 0x100: 243024011f34SLudovic Desroches host->caps.has_bad_data_ordering = 0; 243124011f34SLudovic Desroches host->caps.need_reset_after_xfer = 0; 24327789a98aSGustavo A. R. Silva /* Fall through */ 243324011f34SLudovic Desroches case 0x0: 2434796211b7SLudovic Desroches break; 2435796211b7SLudovic Desroches default: 2436faf8180bSLudovic Desroches host->caps.has_pdc = 0; 2437796211b7SLudovic Desroches dev_warn(&host->pdev->dev, 2438796211b7SLudovic Desroches "Unmanaged mci version, set minimum capabilities\n"); 2439796211b7SLudovic Desroches break; 2440796211b7SLudovic Desroches } 2441796211b7SLudovic Desroches } 244274465b4fSDan Williams 2443ab050b92Sludovic.desroches@atmel.com static int atmci_probe(struct platform_device *pdev) 24447d2be074SHaavard Skinnemoen { 24457d2be074SHaavard Skinnemoen struct mci_platform_data *pdata; 24467d2be074SHaavard Skinnemoen struct atmel_mci *host; 24477d2be074SHaavard Skinnemoen struct resource *regs; 2448965ebf33SHaavard Skinnemoen unsigned int nr_slots; 24497d2be074SHaavard Skinnemoen int irq; 2450528bc780SPramod Gurav int ret, i; 24517d2be074SHaavard Skinnemoen 24527d2be074SHaavard Skinnemoen regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 24537d2be074SHaavard Skinnemoen if (!regs) 24547d2be074SHaavard Skinnemoen return -ENXIO; 24557d2be074SHaavard Skinnemoen pdata = pdev->dev.platform_data; 2456e919fd20SLudovic Desroches if (!pdata) { 2457e919fd20SLudovic Desroches pdata = atmci_of_init(pdev); 2458e919fd20SLudovic Desroches if (IS_ERR(pdata)) { 2459e919fd20SLudovic Desroches dev_err(&pdev->dev, "platform data not available\n"); 2460e919fd20SLudovic Desroches return PTR_ERR(pdata); 2461e919fd20SLudovic Desroches } 2462e919fd20SLudovic Desroches } 2463e919fd20SLudovic Desroches 24647d2be074SHaavard Skinnemoen irq = platform_get_irq(pdev, 0); 24657d2be074SHaavard Skinnemoen if (irq < 0) 24667d2be074SHaavard Skinnemoen return irq; 24677d2be074SHaavard Skinnemoen 24687bca646eSPramod Gurav host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); 2469965ebf33SHaavard Skinnemoen if (!host) 24707d2be074SHaavard Skinnemoen return -ENOMEM; 24717d2be074SHaavard Skinnemoen 24727d2be074SHaavard Skinnemoen host->pdev = pdev; 2473965ebf33SHaavard Skinnemoen spin_lock_init(&host->lock); 2474965ebf33SHaavard Skinnemoen INIT_LIST_HEAD(&host->queue); 24757d2be074SHaavard Skinnemoen 24767bca646eSPramod Gurav host->mck = devm_clk_get(&pdev->dev, "mci_clk"); 24777bca646eSPramod Gurav if (IS_ERR(host->mck)) 24787bca646eSPramod Gurav return PTR_ERR(host->mck); 24797d2be074SHaavard Skinnemoen 24807bca646eSPramod Gurav host->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); 24817d2be074SHaavard Skinnemoen if (!host->regs) 24827bca646eSPramod Gurav return -ENOMEM; 24837d2be074SHaavard Skinnemoen 2484b3894f26SBoris BREZILLON ret = clk_prepare_enable(host->mck); 2485b3894f26SBoris BREZILLON if (ret) 24867bca646eSPramod Gurav return ret; 24877bca646eSPramod Gurav 248803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 24897d2be074SHaavard Skinnemoen host->bus_hz = clk_get_rate(host->mck); 24907d2be074SHaavard Skinnemoen 24917d2be074SHaavard Skinnemoen host->mapbase = regs->start; 24927d2be074SHaavard Skinnemoen 2493965ebf33SHaavard Skinnemoen tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host); 24947d2be074SHaavard Skinnemoen 249589c8aa20SKay Sievers ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); 2496ae552ab0SWenyou Yang if (ret) { 2497ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 24987bca646eSPramod Gurav return ret; 2499ae552ab0SWenyou Yang } 25007d2be074SHaavard Skinnemoen 2501796211b7SLudovic Desroches /* Get MCI capabilities and set operations according to it */ 2502796211b7SLudovic Desroches atmci_get_cap(host); 2503467e081dSludovic.desroches@atmel.com ret = atmci_configure_dma(host); 2504467e081dSludovic.desroches@atmel.com if (ret == -EPROBE_DEFER) 2505467e081dSludovic.desroches@atmel.com goto err_dma_probe_defer; 2506467e081dSludovic.desroches@atmel.com if (ret == 0) { 2507796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data_dma; 2508796211b7SLudovic Desroches host->submit_data = &atmci_submit_data_dma; 2509796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer_dma; 2510796211b7SLudovic Desroches } else if (host->caps.has_pdc) { 2511796211b7SLudovic Desroches dev_info(&pdev->dev, "using PDC\n"); 2512796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data_pdc; 2513796211b7SLudovic Desroches host->submit_data = &atmci_submit_data_pdc; 2514796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer_pdc; 2515796211b7SLudovic Desroches } else { 2516ef878198SLudovic Desroches dev_info(&pdev->dev, "using PIO\n"); 2517796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data; 2518796211b7SLudovic Desroches host->submit_data = &atmci_submit_data; 2519796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer; 2520796211b7SLudovic Desroches } 2521796211b7SLudovic Desroches 25227d2be074SHaavard Skinnemoen platform_set_drvdata(pdev, host); 25237d2be074SHaavard Skinnemoen 25242ee4f620SKees Cook timer_setup(&host->timer, atmci_timeout_timer, 0); 2525b87cc1b5SLudovic Desroches 2526ae552ab0SWenyou Yang pm_runtime_get_noresume(&pdev->dev); 2527ae552ab0SWenyou Yang pm_runtime_set_active(&pdev->dev); 2528ae552ab0SWenyou Yang pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY); 2529ae552ab0SWenyou Yang pm_runtime_use_autosuspend(&pdev->dev); 2530ae552ab0SWenyou Yang pm_runtime_enable(&pdev->dev); 2531ae552ab0SWenyou Yang 2532965ebf33SHaavard Skinnemoen /* We need at least one slot to succeed */ 2533965ebf33SHaavard Skinnemoen nr_slots = 0; 2534965ebf33SHaavard Skinnemoen ret = -ENODEV; 2535965ebf33SHaavard Skinnemoen if (pdata->slot[0].bus_width) { 2536965ebf33SHaavard Skinnemoen ret = atmci_init_slot(host, &pdata->slot[0], 25372c96a293SLudovic Desroches 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); 25387a90dcc2SLudovic Desroches if (!ret) { 2539965ebf33SHaavard Skinnemoen nr_slots++; 25407a90dcc2SLudovic Desroches host->buf_size = host->slot[0]->mmc->max_req_size; 25417a90dcc2SLudovic Desroches } 25427d2be074SHaavard Skinnemoen } 2543965ebf33SHaavard Skinnemoen if (pdata->slot[1].bus_width) { 2544965ebf33SHaavard Skinnemoen ret = atmci_init_slot(host, &pdata->slot[1], 25452c96a293SLudovic Desroches 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); 25467a90dcc2SLudovic Desroches if (!ret) { 2547965ebf33SHaavard Skinnemoen nr_slots++; 25487a90dcc2SLudovic Desroches if (host->slot[1]->mmc->max_req_size > host->buf_size) 25497a90dcc2SLudovic Desroches host->buf_size = 25507a90dcc2SLudovic Desroches host->slot[1]->mmc->max_req_size; 25517a90dcc2SLudovic Desroches } 25527d2be074SHaavard Skinnemoen } 25537d2be074SHaavard Skinnemoen 255404d699c3SRob Emanuele if (!nr_slots) { 255504d699c3SRob Emanuele dev_err(&pdev->dev, "init failed: no slot defined\n"); 2556965ebf33SHaavard Skinnemoen goto err_init_slot; 255704d699c3SRob Emanuele } 25587d2be074SHaavard Skinnemoen 25597a90dcc2SLudovic Desroches if (!host->caps.has_rwproof) { 25607a90dcc2SLudovic Desroches host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, 25617a90dcc2SLudovic Desroches &host->buf_phys_addr, 25627a90dcc2SLudovic Desroches GFP_KERNEL); 25637a90dcc2SLudovic Desroches if (!host->buffer) { 25647a90dcc2SLudovic Desroches ret = -ENOMEM; 25657a90dcc2SLudovic Desroches dev_err(&pdev->dev, "buffer allocation failed\n"); 2566528bc780SPramod Gurav goto err_dma_alloc; 25677a90dcc2SLudovic Desroches } 25687a90dcc2SLudovic Desroches } 25697a90dcc2SLudovic Desroches 2570965ebf33SHaavard Skinnemoen dev_info(&pdev->dev, 2571965ebf33SHaavard Skinnemoen "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", 2572965ebf33SHaavard Skinnemoen host->mapbase, irq, nr_slots); 2573deec9ae3SHaavard Skinnemoen 2574ae552ab0SWenyou Yang pm_runtime_mark_last_busy(&host->pdev->dev); 2575ae552ab0SWenyou Yang pm_runtime_put_autosuspend(&pdev->dev); 2576ae552ab0SWenyou Yang 25777d2be074SHaavard Skinnemoen return 0; 25787d2be074SHaavard Skinnemoen 2579528bc780SPramod Gurav err_dma_alloc: 2580528bc780SPramod Gurav for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 2581528bc780SPramod Gurav if (host->slot[i]) 2582528bc780SPramod Gurav atmci_cleanup_slot(host->slot[i], i); 2583528bc780SPramod Gurav } 2584965ebf33SHaavard Skinnemoen err_init_slot: 2585ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2586ae552ab0SWenyou Yang 2587ae552ab0SWenyou Yang pm_runtime_disable(&pdev->dev); 2588ae552ab0SWenyou Yang pm_runtime_put_noidle(&pdev->dev); 2589ae552ab0SWenyou Yang 2590528bc780SPramod Gurav del_timer_sync(&host->timer); 2591467e081dSludovic.desroches@atmel.com if (!IS_ERR(host->dma.chan)) 259274465b4fSDan Williams dma_release_channel(host->dma.chan); 2593467e081dSludovic.desroches@atmel.com err_dma_probe_defer: 2594965ebf33SHaavard Skinnemoen free_irq(irq, host); 25957d2be074SHaavard Skinnemoen return ret; 25967d2be074SHaavard Skinnemoen } 25977d2be074SHaavard Skinnemoen 2598ab050b92Sludovic.desroches@atmel.com static int atmci_remove(struct platform_device *pdev) 25997d2be074SHaavard Skinnemoen { 26007d2be074SHaavard Skinnemoen struct atmel_mci *host = platform_get_drvdata(pdev); 2601965ebf33SHaavard Skinnemoen unsigned int i; 26027d2be074SHaavard Skinnemoen 2603ae552ab0SWenyou Yang pm_runtime_get_sync(&pdev->dev); 2604ae552ab0SWenyou Yang 26057a90dcc2SLudovic Desroches if (host->buffer) 26067a90dcc2SLudovic Desroches dma_free_coherent(&pdev->dev, host->buf_size, 26077a90dcc2SLudovic Desroches host->buffer, host->buf_phys_addr); 26087a90dcc2SLudovic Desroches 26092c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 2610965ebf33SHaavard Skinnemoen if (host->slot[i]) 2611965ebf33SHaavard Skinnemoen atmci_cleanup_slot(host->slot[i], i); 26127d2be074SHaavard Skinnemoen } 26137d2be074SHaavard Skinnemoen 261403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ~0UL); 261503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); 261603fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_SR); 26177d2be074SHaavard Skinnemoen 2618528bc780SPramod Gurav del_timer_sync(&host->timer); 2619467e081dSludovic.desroches@atmel.com if (!IS_ERR(host->dma.chan)) 262074465b4fSDan Williams dma_release_channel(host->dma.chan); 262165e8b083SHaavard Skinnemoen 2622965ebf33SHaavard Skinnemoen free_irq(platform_get_irq(pdev, 0), host); 26237d2be074SHaavard Skinnemoen 2624ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2625ae552ab0SWenyou Yang 2626ae552ab0SWenyou Yang pm_runtime_disable(&pdev->dev); 2627ae552ab0SWenyou Yang pm_runtime_put_noidle(&pdev->dev); 2628ae552ab0SWenyou Yang 26297d2be074SHaavard Skinnemoen return 0; 26307d2be074SHaavard Skinnemoen } 26317d2be074SHaavard Skinnemoen 2632ae552ab0SWenyou Yang #ifdef CONFIG_PM 2633ae552ab0SWenyou Yang static int atmci_runtime_suspend(struct device *dev) 2634ae552ab0SWenyou Yang { 2635ae552ab0SWenyou Yang struct atmel_mci *host = dev_get_drvdata(dev); 2636ae552ab0SWenyou Yang 2637ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2638ae552ab0SWenyou Yang 2639b5b64fa6SWenyou Yang pinctrl_pm_select_sleep_state(dev); 2640b5b64fa6SWenyou Yang 2641ae552ab0SWenyou Yang return 0; 2642ae552ab0SWenyou Yang } 2643ae552ab0SWenyou Yang 2644ae552ab0SWenyou Yang static int atmci_runtime_resume(struct device *dev) 2645ae552ab0SWenyou Yang { 2646ae552ab0SWenyou Yang struct atmel_mci *host = dev_get_drvdata(dev); 2647ae552ab0SWenyou Yang 2648b5b64fa6SWenyou Yang pinctrl_pm_select_default_state(dev); 2649b5b64fa6SWenyou Yang 2650ae552ab0SWenyou Yang return clk_prepare_enable(host->mck); 2651ae552ab0SWenyou Yang } 2652ae552ab0SWenyou Yang #endif 2653ae552ab0SWenyou Yang 2654ae552ab0SWenyou Yang static const struct dev_pm_ops atmci_dev_pm_ops = { 2655ae552ab0SWenyou Yang SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 2656ae552ab0SWenyou Yang pm_runtime_force_resume) 2657c3cb6ba4SLudovic Desroches SET_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL) 2658ae552ab0SWenyou Yang }; 2659ae552ab0SWenyou Yang 26607d2be074SHaavard Skinnemoen static struct platform_driver atmci_driver = { 26615e0fe897Sludovic.desroches@atmel.com .probe = atmci_probe, 2662ab050b92Sludovic.desroches@atmel.com .remove = atmci_remove, 26637d2be074SHaavard Skinnemoen .driver = { 26647d2be074SHaavard Skinnemoen .name = "atmel_mci", 2665e919fd20SLudovic Desroches .of_match_table = of_match_ptr(atmci_dt_ids), 2666ae552ab0SWenyou Yang .pm = &atmci_dev_pm_ops, 26677d2be074SHaavard Skinnemoen }, 26687d2be074SHaavard Skinnemoen }; 26695e0fe897Sludovic.desroches@atmel.com module_platform_driver(atmci_driver); 26707d2be074SHaavard Skinnemoen 26717d2be074SHaavard Skinnemoen MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); 2672e05503efSJean Delvare MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); 26737d2be074SHaavard Skinnemoen MODULE_LICENSE("GPL v2"); 2674