17d2be074SHaavard Skinnemoen /* 27d2be074SHaavard Skinnemoen * Atmel MultiMedia Card Interface driver 37d2be074SHaavard Skinnemoen * 47d2be074SHaavard Skinnemoen * Copyright (C) 2004-2008 Atmel Corporation 57d2be074SHaavard Skinnemoen * 67d2be074SHaavard Skinnemoen * This program is free software; you can redistribute it and/or modify 77d2be074SHaavard Skinnemoen * it under the terms of the GNU General Public License version 2 as 87d2be074SHaavard Skinnemoen * published by the Free Software Foundation. 97d2be074SHaavard Skinnemoen */ 107d2be074SHaavard Skinnemoen #include <linux/blkdev.h> 117d2be074SHaavard Skinnemoen #include <linux/clk.h> 12deec9ae3SHaavard Skinnemoen #include <linux/debugfs.h> 137d2be074SHaavard Skinnemoen #include <linux/device.h> 1465e8b083SHaavard Skinnemoen #include <linux/dmaengine.h> 1565e8b083SHaavard Skinnemoen #include <linux/dma-mapping.h> 16fbfca4b8SBen Nizette #include <linux/err.h> 173c26e170SDavid Brownell #include <linux/gpio.h> 187d2be074SHaavard Skinnemoen #include <linux/init.h> 197d2be074SHaavard Skinnemoen #include <linux/interrupt.h> 207bca646eSPramod Gurav #include <linux/io.h> 217d2be074SHaavard Skinnemoen #include <linux/ioport.h> 227d2be074SHaavard Skinnemoen #include <linux/module.h> 23e919fd20SLudovic Desroches #include <linux/of.h> 24e919fd20SLudovic Desroches #include <linux/of_device.h> 25e919fd20SLudovic Desroches #include <linux/of_gpio.h> 267d2be074SHaavard Skinnemoen #include <linux/platform_device.h> 277d2be074SHaavard Skinnemoen #include <linux/scatterlist.h> 28deec9ae3SHaavard Skinnemoen #include <linux/seq_file.h> 295a0e3ad6STejun Heo #include <linux/slab.h> 30deec9ae3SHaavard Skinnemoen #include <linux/stat.h> 31e2b35f3dSViresh Kumar #include <linux/types.h> 327d2be074SHaavard Skinnemoen 337d2be074SHaavard Skinnemoen #include <linux/mmc/host.h> 342f1d7918SNicolas Ferre #include <linux/mmc/sdio.h> 352635d1baSNicolas Ferre 36c42aa775SNicolas Ferre #include <linux/atmel-mci.h> 37796211b7SLudovic Desroches #include <linux/atmel_pdc.h> 38ae552ab0SWenyou Yang #include <linux/pm.h> 39ae552ab0SWenyou Yang #include <linux/pm_runtime.h> 40b5b64fa6SWenyou Yang #include <linux/pinctrl/consumer.h> 417d2be074SHaavard Skinnemoen 42bf614c7aSArnd Bergmann #include <asm/cacheflush.h> 437d2be074SHaavard Skinnemoen #include <asm/io.h> 447d2be074SHaavard Skinnemoen #include <asm/unaligned.h> 457d2be074SHaavard Skinnemoen 46ec8fc9cfSludovic.desroches@atmel.com /* 47ef4b160fSAndy Shevchenko * Superset of MCI IP registers integrated in Atmel AT91 Processor 48ec8fc9cfSludovic.desroches@atmel.com * Registers and bitfields marked with [2] are only available in MCI2 49ec8fc9cfSludovic.desroches@atmel.com */ 50ec8fc9cfSludovic.desroches@atmel.com 51ec8fc9cfSludovic.desroches@atmel.com /* MCI Register Definitions */ 52ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR 0x0000 /* Control */ 53ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_MCIEN BIT(0) /* MCI Enable */ 54ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_MCIDIS BIT(1) /* MCI Disable */ 55ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_PWSEN BIT(2) /* Power Save Enable */ 56ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_PWSDIS BIT(3) /* Power Save Disable */ 57ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CR_SWRST BIT(7) /* Software Reset */ 58ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR 0x0004 /* Mode */ 59ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ 60ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ 61ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_RDPROOF BIT(11) /* Read Proof */ 62ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_WRPROOF BIT(12) /* Write Proof */ 63ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PDCFBYTE BIT(13) /* Force Byte Transfer */ 64ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PDCPADV BIT(14) /* Padding Value */ 65ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_PDCMODE BIT(15) /* PDC-oriented Mode */ 66ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ 67ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOR 0x0008 /* Data Timeout */ 68ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ 69ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ 70ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCR 0x000c /* SD Card / SDIO */ 71ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCSEL_SLOT_A (0 << 0) /* Select SD slot A */ 72ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCSEL_SLOT_B (1 << 0) /* Select SD slot A */ 73ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCSEL_MASK (3 << 0) 74ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_1BIT (0 << 6) /* 1-bit data bus */ 75ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_4BIT (2 << 6) /* 4-bit data bus */ 76ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_8BIT (3 << 6) /* 8-bit data bus[2] */ 77ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDCBUS_MASK (3 << 6) 78ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ARGR 0x0010 /* Command Argument */ 79ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR 0x0014 /* Command */ 80ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ 81ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_RSPTYP_NONE (0 << 6) /* No response */ 82ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_RSPTYP_48BIT (1 << 6) /* 48-bit response */ 83ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_RSPTYP_136BIT (2 << 6) /* 136-bit response */ 84ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_INIT (1 << 8) /* Initialization command */ 85ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_SYNC (2 << 8) /* Synchronized command */ 86ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_INT (4 << 8) /* Interrupt command */ 87ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SPCMD_INTRESP (5 << 8) /* Interrupt response */ 88ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_OPDCMD (1 << 11) /* Open Drain */ 89ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_MAXLAT_5CYC (0 << 12) /* Max latency 5 cycles */ 90ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_MAXLAT_64CYC (1 << 12) /* Max latency 64 cycles */ 91ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_START_XFER (1 << 16) /* Start data transfer */ 92ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_STOP_XFER (2 << 16) /* Stop data transfer */ 93ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_TRDIR_WRITE (0 << 18) /* Write data */ 94ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_TRDIR_READ (1 << 18) /* Read data */ 95ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_BLOCK (0 << 19) /* Single-block transfer */ 96ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_MULTI_BLOCK (1 << 19) /* Multi-block transfer */ 97ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_STREAM (2 << 19) /* MMC Stream transfer */ 98ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_BYTE (4 << 19) /* SDIO Byte transfer */ 99ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_BLOCK (5 << 19) /* SDIO Block transfer */ 100ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_SUSPEND (1 << 24) /* SDIO Suspend Command */ 101ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDR_SDIO_RESUME (2 << 24) /* SDIO Resume Command */ 102ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKR 0x0018 /* Block */ 103ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ 104ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ 105ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ 106ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ 107ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ 108ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR 0x0020 /* Response 0 */ 109ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR1 0x0024 /* Response 1 */ 110ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR2 0x0028 /* Response 2 */ 111ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RSPR3 0x002c /* Response 3 */ 112ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RDR 0x0030 /* Receive Data */ 113ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_TDR 0x0034 /* Transmit Data */ 114ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SR 0x0040 /* Status */ 115ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_IER 0x0044 /* Interrupt Enable */ 116ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_IDR 0x0048 /* Interrupt Disable */ 117ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_IMR 0x004c /* Interrupt Mask */ 118ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CMDRDY BIT(0) /* Command Ready */ 119ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RXRDY BIT(1) /* Receiver Ready */ 120ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_TXRDY BIT(2) /* Transmitter Ready */ 121ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKE BIT(3) /* Data Block Ended */ 122ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTIP BIT(4) /* Data Transfer In Progress */ 123ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_NOTBUSY BIT(5) /* Data Not Busy */ 124ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ENDRX BIT(6) /* End of RX Buffer */ 125ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ENDTX BIT(7) /* End of TX Buffer */ 126ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDIOIRQA BIT(8) /* SDIO IRQ in slot A */ 127ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDIOIRQB BIT(9) /* SDIO IRQ in slot B */ 128ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_SDIOWAIT BIT(12) /* SDIO Read Wait Operation Status */ 129ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSRCV BIT(13) /* CE-ATA Completion Signal Received */ 130ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RXBUFF BIT(14) /* RX Buffer Full */ 131ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_TXBUFE BIT(15) /* TX Buffer Empty */ 132ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RINDE BIT(16) /* Response Index Error */ 133ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RDIRE BIT(17) /* Response Direction Error */ 134ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RCRCE BIT(18) /* Response CRC Error */ 135ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RENDE BIT(19) /* Response End Bit Error */ 136ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_RTOE BIT(20) /* Response Time-Out Error */ 137ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DCRCE BIT(21) /* Data CRC Error */ 138ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DTOE BIT(22) /* Data Time-Out Error */ 139ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CSTOE BIT(23) /* Completion Signal Time-out Error */ 140ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_BLKOVRE BIT(24) /* DMA Block Overrun Error */ 141ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMADONE BIT(25) /* DMA Transfer Done */ 142ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_FIFOEMPTY BIT(26) /* FIFO Empty Flag */ 143ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_XFRDONE BIT(27) /* Transfer Done Flag */ 144ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ACKRCV BIT(28) /* Boot Operation Acknowledge Received */ 145ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_ACKRCVE BIT(29) /* Boot Operation Acknowledge Error */ 146ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_OVRE BIT(30) /* RX Overrun Error */ 147ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_UNRE BIT(31) /* TX Underrun Error */ 148ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ 149ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ 150ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ 151ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_DMAEN BIT(8) /* DMA Hardware Handshaking Enable */ 152ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG 0x0054 /* Configuration[2] */ 153ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_FIFOMODE_1DATA BIT(0) /* MCI Internal FIFO control mode */ 154ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_FERRCTRL_COR BIT(4) /* Flow Error flag reset control mode */ 155ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_HSMODE BIT(8) /* High Speed Mode */ 156ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_CFG_LSYNC BIT(12) /* Synchronize on the last block */ 157ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ 158ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WP_EN BIT(0) /* WP Enable */ 159ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ 160ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ 161ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_GET_WP_VS(x) ((x) & 0x0f) 162ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) 163ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_VERSION 0x00FC /* Version */ 164ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ 165ec8fc9cfSludovic.desroches@atmel.com 166ec8fc9cfSludovic.desroches@atmel.com /* This is not including the FIFO Aperture on MCI2 */ 167ec8fc9cfSludovic.desroches@atmel.com #define ATMCI_REGS_SIZE 0x100 168ec8fc9cfSludovic.desroches@atmel.com 169ec8fc9cfSludovic.desroches@atmel.com /* Register access macros */ 170ec8fc9cfSludovic.desroches@atmel.com #define atmci_readl(port, reg) \ 171ec8fc9cfSludovic.desroches@atmel.com __raw_readl((port)->regs + reg) 172ec8fc9cfSludovic.desroches@atmel.com #define atmci_writel(port, reg, value) \ 173ec8fc9cfSludovic.desroches@atmel.com __raw_writel((value), (port)->regs + reg) 174ec8fc9cfSludovic.desroches@atmel.com 175ae552ab0SWenyou Yang #define AUTOSUSPEND_DELAY 50 176ae552ab0SWenyou Yang 1772c96a293SLudovic Desroches #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) 17865e8b083SHaavard Skinnemoen #define ATMCI_DMA_THRESHOLD 16 1797d2be074SHaavard Skinnemoen 1807d2be074SHaavard Skinnemoen enum { 181f5177547SLudovic Desroches EVENT_CMD_RDY = 0, 1827d2be074SHaavard Skinnemoen EVENT_XFER_COMPLETE, 183f5177547SLudovic Desroches EVENT_NOTBUSY, 184c06ad258SHaavard Skinnemoen EVENT_DATA_ERROR, 185c06ad258SHaavard Skinnemoen }; 186c06ad258SHaavard Skinnemoen 187c06ad258SHaavard Skinnemoen enum atmel_mci_state { 188965ebf33SHaavard Skinnemoen STATE_IDLE = 0, 189965ebf33SHaavard Skinnemoen STATE_SENDING_CMD, 190f5177547SLudovic Desroches STATE_DATA_XFER, 191f5177547SLudovic Desroches STATE_WAITING_NOTBUSY, 192c06ad258SHaavard Skinnemoen STATE_SENDING_STOP, 193f5177547SLudovic Desroches STATE_END_REQUEST, 1947d2be074SHaavard Skinnemoen }; 1957d2be074SHaavard Skinnemoen 196796211b7SLudovic Desroches enum atmci_xfer_dir { 197796211b7SLudovic Desroches XFER_RECEIVE = 0, 198796211b7SLudovic Desroches XFER_TRANSMIT, 199796211b7SLudovic Desroches }; 200796211b7SLudovic Desroches 201796211b7SLudovic Desroches enum atmci_pdc_buf { 202796211b7SLudovic Desroches PDC_FIRST_BUF = 0, 203796211b7SLudovic Desroches PDC_SECOND_BUF, 204796211b7SLudovic Desroches }; 205796211b7SLudovic Desroches 206796211b7SLudovic Desroches struct atmel_mci_caps { 207ccdfe612SHein_Tibosch bool has_dma_conf_reg; 208796211b7SLudovic Desroches bool has_pdc; 209796211b7SLudovic Desroches bool has_cfg_reg; 210796211b7SLudovic Desroches bool has_cstor_reg; 211796211b7SLudovic Desroches bool has_highspeed; 212796211b7SLudovic Desroches bool has_rwproof; 213faf8180bSLudovic Desroches bool has_odd_clk_div; 21424011f34SLudovic Desroches bool has_bad_data_ordering; 21524011f34SLudovic Desroches bool need_reset_after_xfer; 21624011f34SLudovic Desroches bool need_blksz_mul_4; 217077d4073SLudovic Desroches bool need_notbusy_for_read_ops; 218796211b7SLudovic Desroches }; 219796211b7SLudovic Desroches 22065e8b083SHaavard Skinnemoen struct atmel_mci_dma { 22165e8b083SHaavard Skinnemoen struct dma_chan *chan; 22265e8b083SHaavard Skinnemoen struct dma_async_tx_descriptor *data_desc; 22365e8b083SHaavard Skinnemoen }; 22465e8b083SHaavard Skinnemoen 225965ebf33SHaavard Skinnemoen /** 226965ebf33SHaavard Skinnemoen * struct atmel_mci - MMC controller state shared between all slots 227965ebf33SHaavard Skinnemoen * @lock: Spinlock protecting the queue and associated data. 228965ebf33SHaavard Skinnemoen * @regs: Pointer to MMIO registers. 229796211b7SLudovic Desroches * @sg: Scatterlist entry currently being processed by PIO or PDC code. 230965ebf33SHaavard Skinnemoen * @pio_offset: Offset into the current scatterlist entry. 2317a90dcc2SLudovic Desroches * @buffer: Buffer used if we don't have the r/w proof capability. We 2327a90dcc2SLudovic Desroches * don't have the time to switch pdc buffers so we have to use only 2337a90dcc2SLudovic Desroches * one buffer for the full transaction. 2347a90dcc2SLudovic Desroches * @buf_size: size of the buffer. 2357a90dcc2SLudovic Desroches * @phys_buf_addr: buffer address needed for pdc. 236965ebf33SHaavard Skinnemoen * @cur_slot: The slot which is currently using the controller. 237965ebf33SHaavard Skinnemoen * @mrq: The request currently being processed on @cur_slot, 238965ebf33SHaavard Skinnemoen * or NULL if the controller is idle. 239965ebf33SHaavard Skinnemoen * @cmd: The command currently being sent to the card, or NULL. 240965ebf33SHaavard Skinnemoen * @data: The data currently being transferred, or NULL if no data 241965ebf33SHaavard Skinnemoen * transfer is in progress. 242796211b7SLudovic Desroches * @data_size: just data->blocks * data->blksz. 24365e8b083SHaavard Skinnemoen * @dma: DMA client state. 24465e8b083SHaavard Skinnemoen * @data_chan: DMA channel being used for the current data transfer. 245965ebf33SHaavard Skinnemoen * @cmd_status: Snapshot of SR taken upon completion of the current 246965ebf33SHaavard Skinnemoen * command. Only valid when EVENT_CMD_COMPLETE is pending. 247965ebf33SHaavard Skinnemoen * @data_status: Snapshot of SR taken upon completion of the current 248965ebf33SHaavard Skinnemoen * data transfer. Only valid when EVENT_DATA_COMPLETE or 249965ebf33SHaavard Skinnemoen * EVENT_DATA_ERROR is pending. 250965ebf33SHaavard Skinnemoen * @stop_cmdr: Value to be loaded into CMDR when the stop command is 251965ebf33SHaavard Skinnemoen * to be sent. 252965ebf33SHaavard Skinnemoen * @tasklet: Tasklet running the request state machine. 253965ebf33SHaavard Skinnemoen * @pending_events: Bitmask of events flagged by the interrupt handler 254965ebf33SHaavard Skinnemoen * to be processed by the tasklet. 255965ebf33SHaavard Skinnemoen * @completed_events: Bitmask of events which the state machine has 256965ebf33SHaavard Skinnemoen * processed. 257965ebf33SHaavard Skinnemoen * @state: Tasklet state. 258965ebf33SHaavard Skinnemoen * @queue: List of slots waiting for access to the controller. 259965ebf33SHaavard Skinnemoen * @need_clock_update: Update the clock rate before the next request. 260965ebf33SHaavard Skinnemoen * @need_reset: Reset controller before next request. 26124011f34SLudovic Desroches * @timer: Timer to balance the data timeout error flag which cannot rise. 262965ebf33SHaavard Skinnemoen * @mode_reg: Value of the MR register. 26374791a2dSNicolas Ferre * @cfg_reg: Value of the CFG register. 264965ebf33SHaavard Skinnemoen * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus 265965ebf33SHaavard Skinnemoen * rate and timeout calculations. 266965ebf33SHaavard Skinnemoen * @mapbase: Physical address of the MMIO registers. 267965ebf33SHaavard Skinnemoen * @mck: The peripheral bus clock hooked up to the MMC controller. 268965ebf33SHaavard Skinnemoen * @pdev: Platform device associated with the MMC controller. 269965ebf33SHaavard Skinnemoen * @slot: Slots sharing this MMC controller. 270796211b7SLudovic Desroches * @caps: MCI capabilities depending on MCI version. 271796211b7SLudovic Desroches * @prepare_data: function to setup MCI before data transfer which 272796211b7SLudovic Desroches * depends on MCI capabilities. 273796211b7SLudovic Desroches * @submit_data: function to start data transfer which depends on MCI 274796211b7SLudovic Desroches * capabilities. 275796211b7SLudovic Desroches * @stop_transfer: function to stop data transfer which depends on MCI 276796211b7SLudovic Desroches * capabilities. 277965ebf33SHaavard Skinnemoen * 278965ebf33SHaavard Skinnemoen * Locking 279965ebf33SHaavard Skinnemoen * ======= 280965ebf33SHaavard Skinnemoen * 281965ebf33SHaavard Skinnemoen * @lock is a softirq-safe spinlock protecting @queue as well as 282965ebf33SHaavard Skinnemoen * @cur_slot, @mrq and @state. These must always be updated 283965ebf33SHaavard Skinnemoen * at the same time while holding @lock. 284965ebf33SHaavard Skinnemoen * 285965ebf33SHaavard Skinnemoen * @lock also protects mode_reg and need_clock_update since these are 286965ebf33SHaavard Skinnemoen * used to synchronize mode register updates with the queue 287965ebf33SHaavard Skinnemoen * processing. 288965ebf33SHaavard Skinnemoen * 289965ebf33SHaavard Skinnemoen * The @mrq field of struct atmel_mci_slot is also protected by @lock, 290965ebf33SHaavard Skinnemoen * and must always be written at the same time as the slot is added to 291965ebf33SHaavard Skinnemoen * @queue. 292965ebf33SHaavard Skinnemoen * 293965ebf33SHaavard Skinnemoen * @pending_events and @completed_events are accessed using atomic bit 294965ebf33SHaavard Skinnemoen * operations, so they don't need any locking. 295965ebf33SHaavard Skinnemoen * 296965ebf33SHaavard Skinnemoen * None of the fields touched by the interrupt handler need any 297965ebf33SHaavard Skinnemoen * locking. However, ordering is important: Before EVENT_DATA_ERROR or 298965ebf33SHaavard Skinnemoen * EVENT_DATA_COMPLETE is set in @pending_events, all data-related 299965ebf33SHaavard Skinnemoen * interrupts must be disabled and @data_status updated with a 300965ebf33SHaavard Skinnemoen * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the 30125985edcSLucas De Marchi * CMDRDY interrupt must be disabled and @cmd_status updated with a 302965ebf33SHaavard Skinnemoen * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the 303965ebf33SHaavard Skinnemoen * bytes_xfered field of @data must be written. This is ensured by 304965ebf33SHaavard Skinnemoen * using barriers. 305965ebf33SHaavard Skinnemoen */ 3067d2be074SHaavard Skinnemoen struct atmel_mci { 307965ebf33SHaavard Skinnemoen spinlock_t lock; 3087d2be074SHaavard Skinnemoen void __iomem *regs; 3097d2be074SHaavard Skinnemoen 3107d2be074SHaavard Skinnemoen struct scatterlist *sg; 311bdbc5d0cSTerry Barnaby unsigned int sg_len; 3127d2be074SHaavard Skinnemoen unsigned int pio_offset; 3137a90dcc2SLudovic Desroches unsigned int *buffer; 3147a90dcc2SLudovic Desroches unsigned int buf_size; 3157a90dcc2SLudovic Desroches dma_addr_t buf_phys_addr; 3167d2be074SHaavard Skinnemoen 317965ebf33SHaavard Skinnemoen struct atmel_mci_slot *cur_slot; 3187d2be074SHaavard Skinnemoen struct mmc_request *mrq; 3197d2be074SHaavard Skinnemoen struct mmc_command *cmd; 3207d2be074SHaavard Skinnemoen struct mmc_data *data; 321796211b7SLudovic Desroches unsigned int data_size; 3227d2be074SHaavard Skinnemoen 32365e8b083SHaavard Skinnemoen struct atmel_mci_dma dma; 32465e8b083SHaavard Skinnemoen struct dma_chan *data_chan; 325e2b35f3dSViresh Kumar struct dma_slave_config dma_conf; 32665e8b083SHaavard Skinnemoen 3277d2be074SHaavard Skinnemoen u32 cmd_status; 3287d2be074SHaavard Skinnemoen u32 data_status; 3297d2be074SHaavard Skinnemoen u32 stop_cmdr; 3307d2be074SHaavard Skinnemoen 3317d2be074SHaavard Skinnemoen struct tasklet_struct tasklet; 3327d2be074SHaavard Skinnemoen unsigned long pending_events; 3337d2be074SHaavard Skinnemoen unsigned long completed_events; 334c06ad258SHaavard Skinnemoen enum atmel_mci_state state; 335965ebf33SHaavard Skinnemoen struct list_head queue; 3367d2be074SHaavard Skinnemoen 337965ebf33SHaavard Skinnemoen bool need_clock_update; 338965ebf33SHaavard Skinnemoen bool need_reset; 33924011f34SLudovic Desroches struct timer_list timer; 340965ebf33SHaavard Skinnemoen u32 mode_reg; 34174791a2dSNicolas Ferre u32 cfg_reg; 3427d2be074SHaavard Skinnemoen unsigned long bus_hz; 3437d2be074SHaavard Skinnemoen unsigned long mapbase; 3447d2be074SHaavard Skinnemoen struct clk *mck; 3457d2be074SHaavard Skinnemoen struct platform_device *pdev; 346965ebf33SHaavard Skinnemoen 3472c96a293SLudovic Desroches struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS]; 348796211b7SLudovic Desroches 349796211b7SLudovic Desroches struct atmel_mci_caps caps; 350796211b7SLudovic Desroches 351796211b7SLudovic Desroches u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data); 352796211b7SLudovic Desroches void (*submit_data)(struct atmel_mci *host, struct mmc_data *data); 353796211b7SLudovic Desroches void (*stop_transfer)(struct atmel_mci *host); 354965ebf33SHaavard Skinnemoen }; 355965ebf33SHaavard Skinnemoen 356965ebf33SHaavard Skinnemoen /** 357965ebf33SHaavard Skinnemoen * struct atmel_mci_slot - MMC slot state 358965ebf33SHaavard Skinnemoen * @mmc: The mmc_host representing this slot. 359965ebf33SHaavard Skinnemoen * @host: The MMC controller this slot is using. 360965ebf33SHaavard Skinnemoen * @sdc_reg: Value of SDCR to be written before using this slot. 36188ff82edSAnders Grahn * @sdio_irq: SDIO irq mask for this slot. 362965ebf33SHaavard Skinnemoen * @mrq: mmc_request currently being processed or waiting to be 363965ebf33SHaavard Skinnemoen * processed, or NULL when the slot is idle. 364965ebf33SHaavard Skinnemoen * @queue_node: List node for placing this node in the @queue list of 365965ebf33SHaavard Skinnemoen * &struct atmel_mci. 366965ebf33SHaavard Skinnemoen * @clock: Clock rate configured by set_ios(). Protected by host->lock. 367965ebf33SHaavard Skinnemoen * @flags: Random state bits associated with the slot. 368965ebf33SHaavard Skinnemoen * @detect_pin: GPIO pin used for card detection, or negative if not 369965ebf33SHaavard Skinnemoen * available. 370965ebf33SHaavard Skinnemoen * @wp_pin: GPIO pin used for card write protect sending, or negative 371965ebf33SHaavard Skinnemoen * if not available. 3721c1452beSJonas Larsson * @detect_is_active_high: The state of the detect pin when it is active. 373965ebf33SHaavard Skinnemoen * @detect_timer: Timer used for debouncing @detect_pin interrupts. 374965ebf33SHaavard Skinnemoen */ 375965ebf33SHaavard Skinnemoen struct atmel_mci_slot { 376965ebf33SHaavard Skinnemoen struct mmc_host *mmc; 377965ebf33SHaavard Skinnemoen struct atmel_mci *host; 378965ebf33SHaavard Skinnemoen 379965ebf33SHaavard Skinnemoen u32 sdc_reg; 38088ff82edSAnders Grahn u32 sdio_irq; 381965ebf33SHaavard Skinnemoen 382965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 383965ebf33SHaavard Skinnemoen struct list_head queue_node; 384965ebf33SHaavard Skinnemoen 385965ebf33SHaavard Skinnemoen unsigned int clock; 386965ebf33SHaavard Skinnemoen unsigned long flags; 387965ebf33SHaavard Skinnemoen #define ATMCI_CARD_PRESENT 0 388965ebf33SHaavard Skinnemoen #define ATMCI_CARD_NEED_INIT 1 389965ebf33SHaavard Skinnemoen #define ATMCI_SHUTDOWN 2 390965ebf33SHaavard Skinnemoen 391965ebf33SHaavard Skinnemoen int detect_pin; 392965ebf33SHaavard Skinnemoen int wp_pin; 3931c1452beSJonas Larsson bool detect_is_active_high; 394965ebf33SHaavard Skinnemoen 395965ebf33SHaavard Skinnemoen struct timer_list detect_timer; 3967d2be074SHaavard Skinnemoen }; 3977d2be074SHaavard Skinnemoen 3987d2be074SHaavard Skinnemoen #define atmci_test_and_clear_pending(host, event) \ 3997d2be074SHaavard Skinnemoen test_and_clear_bit(event, &host->pending_events) 4007d2be074SHaavard Skinnemoen #define atmci_set_completed(host, event) \ 4017d2be074SHaavard Skinnemoen set_bit(event, &host->completed_events) 4027d2be074SHaavard Skinnemoen #define atmci_set_pending(host, event) \ 4037d2be074SHaavard Skinnemoen set_bit(event, &host->pending_events) 4047d2be074SHaavard Skinnemoen 405deec9ae3SHaavard Skinnemoen /* 406deec9ae3SHaavard Skinnemoen * The debugfs stuff below is mostly optimized away when 407deec9ae3SHaavard Skinnemoen * CONFIG_DEBUG_FS is not set. 408deec9ae3SHaavard Skinnemoen */ 409deec9ae3SHaavard Skinnemoen static int atmci_req_show(struct seq_file *s, void *v) 410deec9ae3SHaavard Skinnemoen { 411965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = s->private; 412965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 413deec9ae3SHaavard Skinnemoen struct mmc_command *cmd; 414deec9ae3SHaavard Skinnemoen struct mmc_command *stop; 415deec9ae3SHaavard Skinnemoen struct mmc_data *data; 416deec9ae3SHaavard Skinnemoen 417deec9ae3SHaavard Skinnemoen /* Make sure we get a consistent snapshot */ 418965ebf33SHaavard Skinnemoen spin_lock_bh(&slot->host->lock); 419965ebf33SHaavard Skinnemoen mrq = slot->mrq; 420deec9ae3SHaavard Skinnemoen 421deec9ae3SHaavard Skinnemoen if (mrq) { 422deec9ae3SHaavard Skinnemoen cmd = mrq->cmd; 423deec9ae3SHaavard Skinnemoen data = mrq->data; 424deec9ae3SHaavard Skinnemoen stop = mrq->stop; 425deec9ae3SHaavard Skinnemoen 426deec9ae3SHaavard Skinnemoen if (cmd) 427deec9ae3SHaavard Skinnemoen seq_printf(s, 428deec9ae3SHaavard Skinnemoen "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 429deec9ae3SHaavard Skinnemoen cmd->opcode, cmd->arg, cmd->flags, 430deec9ae3SHaavard Skinnemoen cmd->resp[0], cmd->resp[1], cmd->resp[2], 431d586ebbbSNicolas Ferre cmd->resp[3], cmd->error); 432deec9ae3SHaavard Skinnemoen if (data) 433deec9ae3SHaavard Skinnemoen seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 434deec9ae3SHaavard Skinnemoen data->bytes_xfered, data->blocks, 435deec9ae3SHaavard Skinnemoen data->blksz, data->flags, data->error); 436deec9ae3SHaavard Skinnemoen if (stop) 437deec9ae3SHaavard Skinnemoen seq_printf(s, 438deec9ae3SHaavard Skinnemoen "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 439deec9ae3SHaavard Skinnemoen stop->opcode, stop->arg, stop->flags, 440deec9ae3SHaavard Skinnemoen stop->resp[0], stop->resp[1], stop->resp[2], 441d586ebbbSNicolas Ferre stop->resp[3], stop->error); 442deec9ae3SHaavard Skinnemoen } 443deec9ae3SHaavard Skinnemoen 444965ebf33SHaavard Skinnemoen spin_unlock_bh(&slot->host->lock); 445deec9ae3SHaavard Skinnemoen 446deec9ae3SHaavard Skinnemoen return 0; 447deec9ae3SHaavard Skinnemoen } 448deec9ae3SHaavard Skinnemoen 449deec9ae3SHaavard Skinnemoen static int atmci_req_open(struct inode *inode, struct file *file) 450deec9ae3SHaavard Skinnemoen { 451deec9ae3SHaavard Skinnemoen return single_open(file, atmci_req_show, inode->i_private); 452deec9ae3SHaavard Skinnemoen } 453deec9ae3SHaavard Skinnemoen 454deec9ae3SHaavard Skinnemoen static const struct file_operations atmci_req_fops = { 455deec9ae3SHaavard Skinnemoen .owner = THIS_MODULE, 456deec9ae3SHaavard Skinnemoen .open = atmci_req_open, 457deec9ae3SHaavard Skinnemoen .read = seq_read, 458deec9ae3SHaavard Skinnemoen .llseek = seq_lseek, 459deec9ae3SHaavard Skinnemoen .release = single_release, 460deec9ae3SHaavard Skinnemoen }; 461deec9ae3SHaavard Skinnemoen 462deec9ae3SHaavard Skinnemoen static void atmci_show_status_reg(struct seq_file *s, 463deec9ae3SHaavard Skinnemoen const char *regname, u32 value) 464deec9ae3SHaavard Skinnemoen { 465deec9ae3SHaavard Skinnemoen static const char *sr_bit[] = { 466deec9ae3SHaavard Skinnemoen [0] = "CMDRDY", 467deec9ae3SHaavard Skinnemoen [1] = "RXRDY", 468deec9ae3SHaavard Skinnemoen [2] = "TXRDY", 469deec9ae3SHaavard Skinnemoen [3] = "BLKE", 470deec9ae3SHaavard Skinnemoen [4] = "DTIP", 471deec9ae3SHaavard Skinnemoen [5] = "NOTBUSY", 47204d699c3SRob Emanuele [6] = "ENDRX", 47304d699c3SRob Emanuele [7] = "ENDTX", 474deec9ae3SHaavard Skinnemoen [8] = "SDIOIRQA", 475deec9ae3SHaavard Skinnemoen [9] = "SDIOIRQB", 47604d699c3SRob Emanuele [12] = "SDIOWAIT", 47704d699c3SRob Emanuele [14] = "RXBUFF", 47804d699c3SRob Emanuele [15] = "TXBUFE", 479deec9ae3SHaavard Skinnemoen [16] = "RINDE", 480deec9ae3SHaavard Skinnemoen [17] = "RDIRE", 481deec9ae3SHaavard Skinnemoen [18] = "RCRCE", 482deec9ae3SHaavard Skinnemoen [19] = "RENDE", 483deec9ae3SHaavard Skinnemoen [20] = "RTOE", 484deec9ae3SHaavard Skinnemoen [21] = "DCRCE", 485deec9ae3SHaavard Skinnemoen [22] = "DTOE", 48604d699c3SRob Emanuele [23] = "CSTOE", 48704d699c3SRob Emanuele [24] = "BLKOVRE", 48804d699c3SRob Emanuele [25] = "DMADONE", 48904d699c3SRob Emanuele [26] = "FIFOEMPTY", 49004d699c3SRob Emanuele [27] = "XFRDONE", 491deec9ae3SHaavard Skinnemoen [30] = "OVRE", 492deec9ae3SHaavard Skinnemoen [31] = "UNRE", 493deec9ae3SHaavard Skinnemoen }; 494deec9ae3SHaavard Skinnemoen unsigned int i; 495deec9ae3SHaavard Skinnemoen 496deec9ae3SHaavard Skinnemoen seq_printf(s, "%s:\t0x%08x", regname, value); 497deec9ae3SHaavard Skinnemoen for (i = 0; i < ARRAY_SIZE(sr_bit); i++) { 498deec9ae3SHaavard Skinnemoen if (value & (1 << i)) { 499deec9ae3SHaavard Skinnemoen if (sr_bit[i]) 500deec9ae3SHaavard Skinnemoen seq_printf(s, " %s", sr_bit[i]); 501deec9ae3SHaavard Skinnemoen else 502deec9ae3SHaavard Skinnemoen seq_puts(s, " UNKNOWN"); 503deec9ae3SHaavard Skinnemoen } 504deec9ae3SHaavard Skinnemoen } 505deec9ae3SHaavard Skinnemoen seq_putc(s, '\n'); 506deec9ae3SHaavard Skinnemoen } 507deec9ae3SHaavard Skinnemoen 508deec9ae3SHaavard Skinnemoen static int atmci_regs_show(struct seq_file *s, void *v) 509deec9ae3SHaavard Skinnemoen { 510deec9ae3SHaavard Skinnemoen struct atmel_mci *host = s->private; 511deec9ae3SHaavard Skinnemoen u32 *buf; 512b3894f26SBoris BREZILLON int ret = 0; 513b3894f26SBoris BREZILLON 514deec9ae3SHaavard Skinnemoen 5152c96a293SLudovic Desroches buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL); 516deec9ae3SHaavard Skinnemoen if (!buf) 517deec9ae3SHaavard Skinnemoen return -ENOMEM; 518deec9ae3SHaavard Skinnemoen 519ae552ab0SWenyou Yang pm_runtime_get_sync(&host->pdev->dev); 520ae552ab0SWenyou Yang 521965ebf33SHaavard Skinnemoen /* 522965ebf33SHaavard Skinnemoen * Grab a more or less consistent snapshot. Note that we're 523965ebf33SHaavard Skinnemoen * not disabling interrupts, so IMR and SR may not be 524965ebf33SHaavard Skinnemoen * consistent. 525965ebf33SHaavard Skinnemoen */ 526965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 5272c96a293SLudovic Desroches memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); 528965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 529deec9ae3SHaavard Skinnemoen 530ae552ab0SWenyou Yang pm_runtime_mark_last_busy(&host->pdev->dev); 531ae552ab0SWenyou Yang pm_runtime_put_autosuspend(&host->pdev->dev); 532b3894f26SBoris BREZILLON 5338a4de07eSNicolas Ferre seq_printf(s, "MR:\t0x%08x%s%s ", 5342c96a293SLudovic Desroches buf[ATMCI_MR / 4], 5352c96a293SLudovic Desroches buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", 5368a4de07eSNicolas Ferre buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : ""); 5378a4de07eSNicolas Ferre if (host->caps.has_odd_clk_div) 5388a4de07eSNicolas Ferre seq_printf(s, "{CLKDIV,CLKODD}=%u\n", 5398a4de07eSNicolas Ferre ((buf[ATMCI_MR / 4] & 0xff) << 1) 5408a4de07eSNicolas Ferre | ((buf[ATMCI_MR / 4] >> 16) & 1)); 5418a4de07eSNicolas Ferre else 5428a4de07eSNicolas Ferre seq_printf(s, "CLKDIV=%u\n", 5438a4de07eSNicolas Ferre (buf[ATMCI_MR / 4] & 0xff)); 5442c96a293SLudovic Desroches seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]); 5452c96a293SLudovic Desroches seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); 5462c96a293SLudovic Desroches seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]); 547deec9ae3SHaavard Skinnemoen seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", 5482c96a293SLudovic Desroches buf[ATMCI_BLKR / 4], 5492c96a293SLudovic Desroches buf[ATMCI_BLKR / 4] & 0xffff, 5502c96a293SLudovic Desroches (buf[ATMCI_BLKR / 4] >> 16) & 0xffff); 551796211b7SLudovic Desroches if (host->caps.has_cstor_reg) 5522c96a293SLudovic Desroches seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]); 553deec9ae3SHaavard Skinnemoen 554deec9ae3SHaavard Skinnemoen /* Don't read RSPR and RDR; it will consume the data there */ 555deec9ae3SHaavard Skinnemoen 5562c96a293SLudovic Desroches atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]); 5572c96a293SLudovic Desroches atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]); 558deec9ae3SHaavard Skinnemoen 559ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) { 56074791a2dSNicolas Ferre u32 val; 56174791a2dSNicolas Ferre 5622c96a293SLudovic Desroches val = buf[ATMCI_DMA / 4]; 56374791a2dSNicolas Ferre seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n", 56474791a2dSNicolas Ferre val, val & 3, 56574791a2dSNicolas Ferre ((val >> 4) & 3) ? 56674791a2dSNicolas Ferre 1 << (((val >> 4) & 3) + 1) : 1, 5672c96a293SLudovic Desroches val & ATMCI_DMAEN ? " DMAEN" : ""); 568796211b7SLudovic Desroches } 569796211b7SLudovic Desroches if (host->caps.has_cfg_reg) { 570796211b7SLudovic Desroches u32 val; 57174791a2dSNicolas Ferre 5722c96a293SLudovic Desroches val = buf[ATMCI_CFG / 4]; 57374791a2dSNicolas Ferre seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n", 57474791a2dSNicolas Ferre val, 5752c96a293SLudovic Desroches val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", 5762c96a293SLudovic Desroches val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", 5772c96a293SLudovic Desroches val & ATMCI_CFG_HSMODE ? " HSMODE" : "", 5782c96a293SLudovic Desroches val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); 57974791a2dSNicolas Ferre } 58074791a2dSNicolas Ferre 581b17339a1SHaavard Skinnemoen kfree(buf); 582b17339a1SHaavard Skinnemoen 583b3894f26SBoris BREZILLON return ret; 584deec9ae3SHaavard Skinnemoen } 585deec9ae3SHaavard Skinnemoen 586deec9ae3SHaavard Skinnemoen static int atmci_regs_open(struct inode *inode, struct file *file) 587deec9ae3SHaavard Skinnemoen { 588deec9ae3SHaavard Skinnemoen return single_open(file, atmci_regs_show, inode->i_private); 589deec9ae3SHaavard Skinnemoen } 590deec9ae3SHaavard Skinnemoen 591deec9ae3SHaavard Skinnemoen static const struct file_operations atmci_regs_fops = { 592deec9ae3SHaavard Skinnemoen .owner = THIS_MODULE, 593deec9ae3SHaavard Skinnemoen .open = atmci_regs_open, 594deec9ae3SHaavard Skinnemoen .read = seq_read, 595deec9ae3SHaavard Skinnemoen .llseek = seq_lseek, 596deec9ae3SHaavard Skinnemoen .release = single_release, 597deec9ae3SHaavard Skinnemoen }; 598deec9ae3SHaavard Skinnemoen 599965ebf33SHaavard Skinnemoen static void atmci_init_debugfs(struct atmel_mci_slot *slot) 600deec9ae3SHaavard Skinnemoen { 601965ebf33SHaavard Skinnemoen struct mmc_host *mmc = slot->mmc; 602965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 603deec9ae3SHaavard Skinnemoen struct dentry *root; 604deec9ae3SHaavard Skinnemoen struct dentry *node; 605deec9ae3SHaavard Skinnemoen 606deec9ae3SHaavard Skinnemoen root = mmc->debugfs_root; 607deec9ae3SHaavard Skinnemoen if (!root) 608deec9ae3SHaavard Skinnemoen return; 609deec9ae3SHaavard Skinnemoen 610deec9ae3SHaavard Skinnemoen node = debugfs_create_file("regs", S_IRUSR, root, host, 611deec9ae3SHaavard Skinnemoen &atmci_regs_fops); 612deec9ae3SHaavard Skinnemoen if (IS_ERR(node)) 613deec9ae3SHaavard Skinnemoen return; 614deec9ae3SHaavard Skinnemoen if (!node) 615deec9ae3SHaavard Skinnemoen goto err; 616deec9ae3SHaavard Skinnemoen 617965ebf33SHaavard Skinnemoen node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops); 618deec9ae3SHaavard Skinnemoen if (!node) 619deec9ae3SHaavard Skinnemoen goto err; 620deec9ae3SHaavard Skinnemoen 621c06ad258SHaavard Skinnemoen node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 622c06ad258SHaavard Skinnemoen if (!node) 623c06ad258SHaavard Skinnemoen goto err; 624c06ad258SHaavard Skinnemoen 625deec9ae3SHaavard Skinnemoen node = debugfs_create_x32("pending_events", S_IRUSR, root, 626deec9ae3SHaavard Skinnemoen (u32 *)&host->pending_events); 627deec9ae3SHaavard Skinnemoen if (!node) 628deec9ae3SHaavard Skinnemoen goto err; 629deec9ae3SHaavard Skinnemoen 630deec9ae3SHaavard Skinnemoen node = debugfs_create_x32("completed_events", S_IRUSR, root, 631deec9ae3SHaavard Skinnemoen (u32 *)&host->completed_events); 632deec9ae3SHaavard Skinnemoen if (!node) 633deec9ae3SHaavard Skinnemoen goto err; 634deec9ae3SHaavard Skinnemoen 635deec9ae3SHaavard Skinnemoen return; 636deec9ae3SHaavard Skinnemoen 637deec9ae3SHaavard Skinnemoen err: 638965ebf33SHaavard Skinnemoen dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 639deec9ae3SHaavard Skinnemoen } 6407d2be074SHaavard Skinnemoen 641e919fd20SLudovic Desroches #if defined(CONFIG_OF) 642e919fd20SLudovic Desroches static const struct of_device_id atmci_dt_ids[] = { 643e919fd20SLudovic Desroches { .compatible = "atmel,hsmci" }, 644e919fd20SLudovic Desroches { /* sentinel */ } 645e919fd20SLudovic Desroches }; 646e919fd20SLudovic Desroches 647e919fd20SLudovic Desroches MODULE_DEVICE_TABLE(of, atmci_dt_ids); 648e919fd20SLudovic Desroches 649c3be1efdSBill Pemberton static struct mci_platform_data* 650e919fd20SLudovic Desroches atmci_of_init(struct platform_device *pdev) 651e919fd20SLudovic Desroches { 652e919fd20SLudovic Desroches struct device_node *np = pdev->dev.of_node; 653e919fd20SLudovic Desroches struct device_node *cnp; 654e919fd20SLudovic Desroches struct mci_platform_data *pdata; 655e919fd20SLudovic Desroches u32 slot_id; 656e919fd20SLudovic Desroches 657e919fd20SLudovic Desroches if (!np) { 658e919fd20SLudovic Desroches dev_err(&pdev->dev, "device node not found\n"); 659e919fd20SLudovic Desroches return ERR_PTR(-EINVAL); 660e919fd20SLudovic Desroches } 661e919fd20SLudovic Desroches 662e919fd20SLudovic Desroches pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 6639b344ba4SMarkus Elfring if (!pdata) 664e919fd20SLudovic Desroches return ERR_PTR(-ENOMEM); 665e919fd20SLudovic Desroches 666e919fd20SLudovic Desroches for_each_child_of_node(np, cnp) { 667e919fd20SLudovic Desroches if (of_property_read_u32(cnp, "reg", &slot_id)) { 668bf892de9SRob Herring dev_warn(&pdev->dev, "reg property is missing for %pOF\n", 669bf892de9SRob Herring cnp); 670e919fd20SLudovic Desroches continue; 671e919fd20SLudovic Desroches } 672e919fd20SLudovic Desroches 673e919fd20SLudovic Desroches if (slot_id >= ATMCI_MAX_NR_SLOTS) { 674e919fd20SLudovic Desroches dev_warn(&pdev->dev, "can't have more than %d slots\n", 675e919fd20SLudovic Desroches ATMCI_MAX_NR_SLOTS); 6767366419bSJulia Lawall of_node_put(cnp); 677e919fd20SLudovic Desroches break; 678e919fd20SLudovic Desroches } 679e919fd20SLudovic Desroches 680e919fd20SLudovic Desroches if (of_property_read_u32(cnp, "bus-width", 681e919fd20SLudovic Desroches &pdata->slot[slot_id].bus_width)) 682e919fd20SLudovic Desroches pdata->slot[slot_id].bus_width = 1; 683e919fd20SLudovic Desroches 684e919fd20SLudovic Desroches pdata->slot[slot_id].detect_pin = 685e919fd20SLudovic Desroches of_get_named_gpio(cnp, "cd-gpios", 0); 686e919fd20SLudovic Desroches 687e919fd20SLudovic Desroches pdata->slot[slot_id].detect_is_active_high = 688e919fd20SLudovic Desroches of_property_read_bool(cnp, "cd-inverted"); 689e919fd20SLudovic Desroches 69076d55564STimo Kokkonen pdata->slot[slot_id].non_removable = 69176d55564STimo Kokkonen of_property_read_bool(cnp, "non-removable"); 69276d55564STimo Kokkonen 693e919fd20SLudovic Desroches pdata->slot[slot_id].wp_pin = 694e919fd20SLudovic Desroches of_get_named_gpio(cnp, "wp-gpios", 0); 695e919fd20SLudovic Desroches } 696e919fd20SLudovic Desroches 697e919fd20SLudovic Desroches return pdata; 698e919fd20SLudovic Desroches } 699e919fd20SLudovic Desroches #else /* CONFIG_OF */ 700e919fd20SLudovic Desroches static inline struct mci_platform_data* 701e919fd20SLudovic Desroches atmci_of_init(struct platform_device *dev) 702e919fd20SLudovic Desroches { 703e919fd20SLudovic Desroches return ERR_PTR(-EINVAL); 704e919fd20SLudovic Desroches } 705e919fd20SLudovic Desroches #endif 706e919fd20SLudovic Desroches 7077a90dcc2SLudovic Desroches static inline unsigned int atmci_get_version(struct atmel_mci *host) 7087a90dcc2SLudovic Desroches { 7097a90dcc2SLudovic Desroches return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; 7107a90dcc2SLudovic Desroches } 7117a90dcc2SLudovic Desroches 712447dc0d2Sludovic.desroches@atmel.com /* 713447dc0d2Sludovic.desroches@atmel.com * Fix sconfig's burst size according to atmel MCI. We need to convert them as: 714447dc0d2Sludovic.desroches@atmel.com * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. 715447dc0d2Sludovic.desroches@atmel.com * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2, 716447dc0d2Sludovic.desroches@atmel.com * 8 -> 3, 16 -> 4. 717447dc0d2Sludovic.desroches@atmel.com * 718447dc0d2Sludovic.desroches@atmel.com * This can be done by finding most significant bit set. 719447dc0d2Sludovic.desroches@atmel.com */ 720447dc0d2Sludovic.desroches@atmel.com static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, 721447dc0d2Sludovic.desroches@atmel.com unsigned int maxburst) 722447dc0d2Sludovic.desroches@atmel.com { 723447dc0d2Sludovic.desroches@atmel.com unsigned int version = atmci_get_version(host); 724447dc0d2Sludovic.desroches@atmel.com unsigned int offset = 2; 725447dc0d2Sludovic.desroches@atmel.com 726447dc0d2Sludovic.desroches@atmel.com if (version >= 0x600) 727447dc0d2Sludovic.desroches@atmel.com offset = 1; 728447dc0d2Sludovic.desroches@atmel.com 729447dc0d2Sludovic.desroches@atmel.com if (maxburst > 1) 730447dc0d2Sludovic.desroches@atmel.com return fls(maxburst) - offset; 731447dc0d2Sludovic.desroches@atmel.com else 732447dc0d2Sludovic.desroches@atmel.com return 0; 733447dc0d2Sludovic.desroches@atmel.com } 734447dc0d2Sludovic.desroches@atmel.com 7352ee4f620SKees Cook static void atmci_timeout_timer(struct timer_list *t) 73624011f34SLudovic Desroches { 73724011f34SLudovic Desroches struct atmel_mci *host; 73824011f34SLudovic Desroches 7392ee4f620SKees Cook host = from_timer(host, t, timer); 74024011f34SLudovic Desroches 74124011f34SLudovic Desroches dev_dbg(&host->pdev->dev, "software timeout\n"); 74224011f34SLudovic Desroches 74324011f34SLudovic Desroches if (host->mrq->cmd->data) { 74424011f34SLudovic Desroches host->mrq->cmd->data->error = -ETIMEDOUT; 74524011f34SLudovic Desroches host->data = NULL; 746c1fa3426SLudovic Desroches /* 747c1fa3426SLudovic Desroches * With some SDIO modules, sometimes DMA transfer hangs. If 748c1fa3426SLudovic Desroches * stop_transfer() is not called then the DMA request is not 749c1fa3426SLudovic Desroches * removed, following ones are queued and never computed. 750c1fa3426SLudovic Desroches */ 751c1fa3426SLudovic Desroches if (host->state == STATE_DATA_XFER) 752c1fa3426SLudovic Desroches host->stop_transfer(host); 75324011f34SLudovic Desroches } else { 75424011f34SLudovic Desroches host->mrq->cmd->error = -ETIMEDOUT; 75524011f34SLudovic Desroches host->cmd = NULL; 75624011f34SLudovic Desroches } 75724011f34SLudovic Desroches host->need_reset = 1; 75824011f34SLudovic Desroches host->state = STATE_END_REQUEST; 75924011f34SLudovic Desroches smp_wmb(); 76024011f34SLudovic Desroches tasklet_schedule(&host->tasklet); 76124011f34SLudovic Desroches } 76224011f34SLudovic Desroches 7632c96a293SLudovic Desroches static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, 7647d2be074SHaavard Skinnemoen unsigned int ns) 7657d2be074SHaavard Skinnemoen { 76666292ad9SLudovic Desroches /* 76766292ad9SLudovic Desroches * It is easier here to use us instead of ns for the timeout, 76866292ad9SLudovic Desroches * it prevents from overflows during calculation. 76966292ad9SLudovic Desroches */ 77066292ad9SLudovic Desroches unsigned int us = DIV_ROUND_UP(ns, 1000); 77166292ad9SLudovic Desroches 77266292ad9SLudovic Desroches /* Maximum clock frequency is host->bus_hz/2 */ 77366292ad9SLudovic Desroches return us * (DIV_ROUND_UP(host->bus_hz, 2000000)); 7747d2be074SHaavard Skinnemoen } 7757d2be074SHaavard Skinnemoen 7767d2be074SHaavard Skinnemoen static void atmci_set_timeout(struct atmel_mci *host, 777965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot, struct mmc_data *data) 7787d2be074SHaavard Skinnemoen { 7797d2be074SHaavard Skinnemoen static unsigned dtomul_to_shift[] = { 7807d2be074SHaavard Skinnemoen 0, 4, 7, 8, 10, 12, 16, 20 7817d2be074SHaavard Skinnemoen }; 7827d2be074SHaavard Skinnemoen unsigned timeout; 7837d2be074SHaavard Skinnemoen unsigned dtocyc; 7847d2be074SHaavard Skinnemoen unsigned dtomul; 7857d2be074SHaavard Skinnemoen 7862c96a293SLudovic Desroches timeout = atmci_ns_to_clocks(host, data->timeout_ns) 7872c96a293SLudovic Desroches + data->timeout_clks; 7887d2be074SHaavard Skinnemoen 7897d2be074SHaavard Skinnemoen for (dtomul = 0; dtomul < 8; dtomul++) { 7907d2be074SHaavard Skinnemoen unsigned shift = dtomul_to_shift[dtomul]; 7917d2be074SHaavard Skinnemoen dtocyc = (timeout + (1 << shift) - 1) >> shift; 7927d2be074SHaavard Skinnemoen if (dtocyc < 15) 7937d2be074SHaavard Skinnemoen break; 7947d2be074SHaavard Skinnemoen } 7957d2be074SHaavard Skinnemoen 7967d2be074SHaavard Skinnemoen if (dtomul >= 8) { 7977d2be074SHaavard Skinnemoen dtomul = 7; 7987d2be074SHaavard Skinnemoen dtocyc = 15; 7997d2be074SHaavard Skinnemoen } 8007d2be074SHaavard Skinnemoen 801965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n", 8027d2be074SHaavard Skinnemoen dtocyc << dtomul_to_shift[dtomul]); 80303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); 8047d2be074SHaavard Skinnemoen } 8057d2be074SHaavard Skinnemoen 8067d2be074SHaavard Skinnemoen /* 8077d2be074SHaavard Skinnemoen * Return mask with command flags to be enabled for this command. 8087d2be074SHaavard Skinnemoen */ 8097d2be074SHaavard Skinnemoen static u32 atmci_prepare_command(struct mmc_host *mmc, 8107d2be074SHaavard Skinnemoen struct mmc_command *cmd) 8117d2be074SHaavard Skinnemoen { 8127d2be074SHaavard Skinnemoen struct mmc_data *data; 8137d2be074SHaavard Skinnemoen u32 cmdr; 8147d2be074SHaavard Skinnemoen 8157d2be074SHaavard Skinnemoen cmd->error = -EINPROGRESS; 8167d2be074SHaavard Skinnemoen 8172c96a293SLudovic Desroches cmdr = ATMCI_CMDR_CMDNB(cmd->opcode); 8187d2be074SHaavard Skinnemoen 8197d2be074SHaavard Skinnemoen if (cmd->flags & MMC_RSP_PRESENT) { 8207d2be074SHaavard Skinnemoen if (cmd->flags & MMC_RSP_136) 8212c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_RSPTYP_136BIT; 8227d2be074SHaavard Skinnemoen else 8232c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_RSPTYP_48BIT; 8247d2be074SHaavard Skinnemoen } 8257d2be074SHaavard Skinnemoen 8267d2be074SHaavard Skinnemoen /* 8277d2be074SHaavard Skinnemoen * This should really be MAXLAT_5 for CMD2 and ACMD41, but 8287d2be074SHaavard Skinnemoen * it's too difficult to determine whether this is an ACMD or 8297d2be074SHaavard Skinnemoen * not. Better make it 64. 8307d2be074SHaavard Skinnemoen */ 8312c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_MAXLAT_64CYC; 8327d2be074SHaavard Skinnemoen 8337d2be074SHaavard Skinnemoen if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) 8342c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_OPDCMD; 8357d2be074SHaavard Skinnemoen 8367d2be074SHaavard Skinnemoen data = cmd->data; 8377d2be074SHaavard Skinnemoen if (data) { 8382c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_START_XFER; 8392f1d7918SNicolas Ferre 8402f1d7918SNicolas Ferre if (cmd->opcode == SD_IO_RW_EXTENDED) { 8412c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_SDIO_BLOCK; 8422f1d7918SNicolas Ferre } else { 843fd551d94SJaehoon Chung if (data->blocks > 1) 8442c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_MULTI_BLOCK; 8457d2be074SHaavard Skinnemoen else 8462c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_BLOCK; 8472f1d7918SNicolas Ferre } 8487d2be074SHaavard Skinnemoen 8497d2be074SHaavard Skinnemoen if (data->flags & MMC_DATA_READ) 8502c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_TRDIR_READ; 8517d2be074SHaavard Skinnemoen } 8527d2be074SHaavard Skinnemoen 8537d2be074SHaavard Skinnemoen return cmdr; 8547d2be074SHaavard Skinnemoen } 8557d2be074SHaavard Skinnemoen 85611d1488bSLudovic Desroches static void atmci_send_command(struct atmel_mci *host, 857965ebf33SHaavard Skinnemoen struct mmc_command *cmd, u32 cmd_flags) 8587d2be074SHaavard Skinnemoen { 8597d2be074SHaavard Skinnemoen WARN_ON(host->cmd); 8607d2be074SHaavard Skinnemoen host->cmd = cmd; 8617d2be074SHaavard Skinnemoen 862965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, 8637d2be074SHaavard Skinnemoen "start command: ARGR=0x%08x CMDR=0x%08x\n", 8647d2be074SHaavard Skinnemoen cmd->arg, cmd_flags); 8657d2be074SHaavard Skinnemoen 86603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_ARGR, cmd->arg); 86703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CMDR, cmd_flags); 8687d2be074SHaavard Skinnemoen } 8697d2be074SHaavard Skinnemoen 8702c96a293SLudovic Desroches static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) 8717d2be074SHaavard Skinnemoen { 8726801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "send stop command\n"); 87311d1488bSLudovic Desroches atmci_send_command(host, data->stop, host->stop_cmdr); 87403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); 8757d2be074SHaavard Skinnemoen } 8767d2be074SHaavard Skinnemoen 877796211b7SLudovic Desroches /* 878796211b7SLudovic Desroches * Configure given PDC buffer taking care of alignement issues. 879796211b7SLudovic Desroches * Update host->data_size and host->sg. 880796211b7SLudovic Desroches */ 881796211b7SLudovic Desroches static void atmci_pdc_set_single_buf(struct atmel_mci *host, 882796211b7SLudovic Desroches enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) 883796211b7SLudovic Desroches { 884796211b7SLudovic Desroches u32 pointer_reg, counter_reg; 8857a90dcc2SLudovic Desroches unsigned int buf_size; 886796211b7SLudovic Desroches 887796211b7SLudovic Desroches if (dir == XFER_RECEIVE) { 888796211b7SLudovic Desroches pointer_reg = ATMEL_PDC_RPR; 889796211b7SLudovic Desroches counter_reg = ATMEL_PDC_RCR; 890796211b7SLudovic Desroches } else { 891796211b7SLudovic Desroches pointer_reg = ATMEL_PDC_TPR; 892796211b7SLudovic Desroches counter_reg = ATMEL_PDC_TCR; 893796211b7SLudovic Desroches } 894796211b7SLudovic Desroches 895796211b7SLudovic Desroches if (buf_nb == PDC_SECOND_BUF) { 8961ebbe3d3SLudovic Desroches pointer_reg += ATMEL_PDC_SCND_BUF_OFF; 8971ebbe3d3SLudovic Desroches counter_reg += ATMEL_PDC_SCND_BUF_OFF; 898796211b7SLudovic Desroches } 899796211b7SLudovic Desroches 9007a90dcc2SLudovic Desroches if (!host->caps.has_rwproof) { 9017a90dcc2SLudovic Desroches buf_size = host->buf_size; 9027a90dcc2SLudovic Desroches atmci_writel(host, pointer_reg, host->buf_phys_addr); 9037a90dcc2SLudovic Desroches } else { 9047a90dcc2SLudovic Desroches buf_size = sg_dma_len(host->sg); 905796211b7SLudovic Desroches atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); 9067a90dcc2SLudovic Desroches } 9077a90dcc2SLudovic Desroches 9087a90dcc2SLudovic Desroches if (host->data_size <= buf_size) { 909796211b7SLudovic Desroches if (host->data_size & 0x3) { 910796211b7SLudovic Desroches /* If size is different from modulo 4, transfer bytes */ 911796211b7SLudovic Desroches atmci_writel(host, counter_reg, host->data_size); 912796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE); 913796211b7SLudovic Desroches } else { 914796211b7SLudovic Desroches /* Else transfer 32-bits words */ 915796211b7SLudovic Desroches atmci_writel(host, counter_reg, host->data_size / 4); 916796211b7SLudovic Desroches } 917796211b7SLudovic Desroches host->data_size = 0; 918796211b7SLudovic Desroches } else { 919796211b7SLudovic Desroches /* We assume the size of a page is 32-bits aligned */ 920341fa4c3SLudovic Desroches atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4); 921341fa4c3SLudovic Desroches host->data_size -= sg_dma_len(host->sg); 922796211b7SLudovic Desroches if (host->data_size) 923796211b7SLudovic Desroches host->sg = sg_next(host->sg); 924796211b7SLudovic Desroches } 925796211b7SLudovic Desroches } 926796211b7SLudovic Desroches 927796211b7SLudovic Desroches /* 928796211b7SLudovic Desroches * Configure PDC buffer according to the data size ie configuring one or two 929796211b7SLudovic Desroches * buffers. Don't use this function if you want to configure only the second 930796211b7SLudovic Desroches * buffer. In this case, use atmci_pdc_set_single_buf. 931796211b7SLudovic Desroches */ 932796211b7SLudovic Desroches static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir) 933796211b7SLudovic Desroches { 934796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF); 935796211b7SLudovic Desroches if (host->data_size) 936796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF); 937796211b7SLudovic Desroches } 938796211b7SLudovic Desroches 939796211b7SLudovic Desroches /* 940796211b7SLudovic Desroches * Unmap sg lists, called when transfer is finished. 941796211b7SLudovic Desroches */ 942796211b7SLudovic Desroches static void atmci_pdc_cleanup(struct atmel_mci *host) 943796211b7SLudovic Desroches { 944796211b7SLudovic Desroches struct mmc_data *data = host->data; 945796211b7SLudovic Desroches 946796211b7SLudovic Desroches if (data) 947796211b7SLudovic Desroches dma_unmap_sg(&host->pdev->dev, 948796211b7SLudovic Desroches data->sg, data->sg_len, 949feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 950796211b7SLudovic Desroches } 951796211b7SLudovic Desroches 952796211b7SLudovic Desroches /* 953796211b7SLudovic Desroches * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after 954796211b7SLudovic Desroches * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY 955796211b7SLudovic Desroches * interrupt needed for both transfer directions. 956796211b7SLudovic Desroches */ 957796211b7SLudovic Desroches static void atmci_pdc_complete(struct atmel_mci *host) 958796211b7SLudovic Desroches { 9597a90dcc2SLudovic Desroches int transfer_size = host->data->blocks * host->data->blksz; 96024011f34SLudovic Desroches int i; 9617a90dcc2SLudovic Desroches 962796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); 9637a90dcc2SLudovic Desroches 9647a90dcc2SLudovic Desroches if ((!host->caps.has_rwproof) 96524011f34SLudovic Desroches && (host->data->flags & MMC_DATA_READ)) { 96624011f34SLudovic Desroches if (host->caps.has_bad_data_ordering) 96724011f34SLudovic Desroches for (i = 0; i < transfer_size; i++) 96824011f34SLudovic Desroches host->buffer[i] = swab32(host->buffer[i]); 9697a90dcc2SLudovic Desroches sg_copy_from_buffer(host->data->sg, host->data->sg_len, 9707a90dcc2SLudovic Desroches host->buffer, transfer_size); 97124011f34SLudovic Desroches } 9727a90dcc2SLudovic Desroches 973796211b7SLudovic Desroches atmci_pdc_cleanup(host); 974796211b7SLudovic Desroches 9756e9e4062SAlexandre Belloni dev_dbg(&host->pdev->dev, "(%s) set pending xfer complete\n", __func__); 976796211b7SLudovic Desroches atmci_set_pending(host, EVENT_XFER_COMPLETE); 977796211b7SLudovic Desroches tasklet_schedule(&host->tasklet); 978796211b7SLudovic Desroches } 979796211b7SLudovic Desroches 98065e8b083SHaavard Skinnemoen static void atmci_dma_cleanup(struct atmel_mci *host) 98165e8b083SHaavard Skinnemoen { 98265e8b083SHaavard Skinnemoen struct mmc_data *data = host->data; 98365e8b083SHaavard Skinnemoen 984009a891bSNicolas Ferre if (data) 985266ac3f2SLinus Walleij dma_unmap_sg(host->dma.chan->device->dev, 986266ac3f2SLinus Walleij data->sg, data->sg_len, 987feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 98865e8b083SHaavard Skinnemoen } 98965e8b083SHaavard Skinnemoen 990796211b7SLudovic Desroches /* 991796211b7SLudovic Desroches * This function is called by the DMA driver from tasklet context. 992796211b7SLudovic Desroches */ 99365e8b083SHaavard Skinnemoen static void atmci_dma_complete(void *arg) 99465e8b083SHaavard Skinnemoen { 99565e8b083SHaavard Skinnemoen struct atmel_mci *host = arg; 99665e8b083SHaavard Skinnemoen struct mmc_data *data = host->data; 99765e8b083SHaavard Skinnemoen 99865e8b083SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "DMA complete\n"); 99965e8b083SHaavard Skinnemoen 1000ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) 100174791a2dSNicolas Ferre /* Disable DMA hardware handshaking on MCI */ 100203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); 100374791a2dSNicolas Ferre 100465e8b083SHaavard Skinnemoen atmci_dma_cleanup(host); 100565e8b083SHaavard Skinnemoen 100665e8b083SHaavard Skinnemoen /* 100765e8b083SHaavard Skinnemoen * If the card was removed, data will be NULL. No point trying 100865e8b083SHaavard Skinnemoen * to send the stop command or waiting for NBUSY in this case. 100965e8b083SHaavard Skinnemoen */ 101065e8b083SHaavard Skinnemoen if (data) { 10116801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 10126801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 101365e8b083SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 101465e8b083SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 101565e8b083SHaavard Skinnemoen 101665e8b083SHaavard Skinnemoen /* 101765e8b083SHaavard Skinnemoen * Regardless of what the documentation says, we have 101865e8b083SHaavard Skinnemoen * to wait for NOTBUSY even after block read 101965e8b083SHaavard Skinnemoen * operations. 102065e8b083SHaavard Skinnemoen * 102165e8b083SHaavard Skinnemoen * When the DMA transfer is complete, the controller 102265e8b083SHaavard Skinnemoen * may still be reading the CRC from the card, i.e. 102365e8b083SHaavard Skinnemoen * the data transfer is still in progress and we 102465e8b083SHaavard Skinnemoen * haven't seen all the potential error bits yet. 102565e8b083SHaavard Skinnemoen * 102665e8b083SHaavard Skinnemoen * The interrupt handler will schedule a different 102765e8b083SHaavard Skinnemoen * tasklet to finish things up when the data transfer 102865e8b083SHaavard Skinnemoen * is completely done. 102965e8b083SHaavard Skinnemoen * 103065e8b083SHaavard Skinnemoen * We may not complete the mmc request here anyway 103165e8b083SHaavard Skinnemoen * because the mmc layer may call back and cause us to 103265e8b083SHaavard Skinnemoen * violate the "don't submit new operations from the 103365e8b083SHaavard Skinnemoen * completion callback" rule of the dma engine 103465e8b083SHaavard Skinnemoen * framework. 103565e8b083SHaavard Skinnemoen */ 103603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 103765e8b083SHaavard Skinnemoen } 103865e8b083SHaavard Skinnemoen } 103965e8b083SHaavard Skinnemoen 1040796211b7SLudovic Desroches /* 1041796211b7SLudovic Desroches * Returns a mask of interrupt flags to be enabled after the whole 1042796211b7SLudovic Desroches * request has been prepared. 1043796211b7SLudovic Desroches */ 1044796211b7SLudovic Desroches static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) 1045796211b7SLudovic Desroches { 1046796211b7SLudovic Desroches u32 iflags; 1047796211b7SLudovic Desroches 1048796211b7SLudovic Desroches data->error = -EINPROGRESS; 1049796211b7SLudovic Desroches 1050796211b7SLudovic Desroches host->sg = data->sg; 1051bdbc5d0cSTerry Barnaby host->sg_len = data->sg_len; 1052796211b7SLudovic Desroches host->data = data; 1053796211b7SLudovic Desroches host->data_chan = NULL; 1054796211b7SLudovic Desroches 1055796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 1056796211b7SLudovic Desroches 1057796211b7SLudovic Desroches /* 1058796211b7SLudovic Desroches * Errata: MMC data write operation with less than 12 1059796211b7SLudovic Desroches * bytes is impossible. 1060796211b7SLudovic Desroches * 1061796211b7SLudovic Desroches * Errata: MCI Transmit Data Register (TDR) FIFO 1062796211b7SLudovic Desroches * corruption when length is not multiple of 4. 1063796211b7SLudovic Desroches */ 1064796211b7SLudovic Desroches if (data->blocks * data->blksz < 12 1065796211b7SLudovic Desroches || (data->blocks * data->blksz) & 3) 1066796211b7SLudovic Desroches host->need_reset = true; 1067796211b7SLudovic Desroches 1068796211b7SLudovic Desroches host->pio_offset = 0; 1069796211b7SLudovic Desroches if (data->flags & MMC_DATA_READ) 1070796211b7SLudovic Desroches iflags |= ATMCI_RXRDY; 1071796211b7SLudovic Desroches else 1072796211b7SLudovic Desroches iflags |= ATMCI_TXRDY; 1073796211b7SLudovic Desroches 1074796211b7SLudovic Desroches return iflags; 1075796211b7SLudovic Desroches } 1076796211b7SLudovic Desroches 1077796211b7SLudovic Desroches /* 1078796211b7SLudovic Desroches * Set interrupt flags and set block length into the MCI mode register even 1079796211b7SLudovic Desroches * if this value is also accessible in the MCI block register. It seems to be 1080796211b7SLudovic Desroches * necessary before the High Speed MCI version. It also map sg and configure 1081796211b7SLudovic Desroches * PDC registers. 1082796211b7SLudovic Desroches */ 1083796211b7SLudovic Desroches static u32 1084796211b7SLudovic Desroches atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) 1085796211b7SLudovic Desroches { 1086796211b7SLudovic Desroches u32 iflags, tmp; 108724011f34SLudovic Desroches int i; 1088796211b7SLudovic Desroches 1089796211b7SLudovic Desroches data->error = -EINPROGRESS; 1090796211b7SLudovic Desroches 1091796211b7SLudovic Desroches host->data = data; 1092796211b7SLudovic Desroches host->sg = data->sg; 1093796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 1094796211b7SLudovic Desroches 1095796211b7SLudovic Desroches /* Enable pdc mode */ 1096796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE); 1097796211b7SLudovic Desroches 1098feeef096SHeiner Kallweit if (data->flags & MMC_DATA_READ) 1099796211b7SLudovic Desroches iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; 1100feeef096SHeiner Kallweit else 1101f5177547SLudovic Desroches iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; 1102796211b7SLudovic Desroches 1103796211b7SLudovic Desroches /* Set BLKLEN */ 1104796211b7SLudovic Desroches tmp = atmci_readl(host, ATMCI_MR); 1105796211b7SLudovic Desroches tmp &= 0x0000ffff; 1106796211b7SLudovic Desroches tmp |= ATMCI_BLKLEN(data->blksz); 1107796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, tmp); 1108796211b7SLudovic Desroches 1109796211b7SLudovic Desroches /* Configure PDC */ 1110796211b7SLudovic Desroches host->data_size = data->blocks * data->blksz; 1111f98e0d5aSShawn Lin dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, 1112feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 11137a90dcc2SLudovic Desroches 11147a90dcc2SLudovic Desroches if ((!host->caps.has_rwproof) 111524011f34SLudovic Desroches && (host->data->flags & MMC_DATA_WRITE)) { 11167a90dcc2SLudovic Desroches sg_copy_to_buffer(host->data->sg, host->data->sg_len, 11177a90dcc2SLudovic Desroches host->buffer, host->data_size); 111824011f34SLudovic Desroches if (host->caps.has_bad_data_ordering) 111924011f34SLudovic Desroches for (i = 0; i < host->data_size; i++) 112024011f34SLudovic Desroches host->buffer[i] = swab32(host->buffer[i]); 112124011f34SLudovic Desroches } 11227a90dcc2SLudovic Desroches 1123796211b7SLudovic Desroches if (host->data_size) 1124feeef096SHeiner Kallweit atmci_pdc_set_both_buf(host, data->flags & MMC_DATA_READ ? 1125feeef096SHeiner Kallweit XFER_RECEIVE : XFER_TRANSMIT); 1126796211b7SLudovic Desroches return iflags; 1127796211b7SLudovic Desroches } 1128796211b7SLudovic Desroches 1129796211b7SLudovic Desroches static u32 113074791a2dSNicolas Ferre atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) 113165e8b083SHaavard Skinnemoen { 113265e8b083SHaavard Skinnemoen struct dma_chan *chan; 113365e8b083SHaavard Skinnemoen struct dma_async_tx_descriptor *desc; 113465e8b083SHaavard Skinnemoen struct scatterlist *sg; 113565e8b083SHaavard Skinnemoen unsigned int i; 113605f5799cSVinod Koul enum dma_transfer_direction slave_dirn; 1137657a77faSAtsushi Nemoto unsigned int sglen; 1138693e5e20SNicolas Ferre u32 maxburst; 1139796211b7SLudovic Desroches u32 iflags; 1140796211b7SLudovic Desroches 1141796211b7SLudovic Desroches data->error = -EINPROGRESS; 1142796211b7SLudovic Desroches 1143796211b7SLudovic Desroches WARN_ON(host->data); 1144796211b7SLudovic Desroches host->sg = NULL; 1145796211b7SLudovic Desroches host->data = data; 1146796211b7SLudovic Desroches 1147796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 114865e8b083SHaavard Skinnemoen 114965e8b083SHaavard Skinnemoen /* 115065e8b083SHaavard Skinnemoen * We don't do DMA on "complex" transfers, i.e. with 115165e8b083SHaavard Skinnemoen * non-word-aligned buffers or lengths. Also, we don't bother 115265e8b083SHaavard Skinnemoen * with all the DMA setup overhead for short transfers. 115365e8b083SHaavard Skinnemoen */ 1154796211b7SLudovic Desroches if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) 1155796211b7SLudovic Desroches return atmci_prepare_data(host, data); 115665e8b083SHaavard Skinnemoen if (data->blksz & 3) 1157796211b7SLudovic Desroches return atmci_prepare_data(host, data); 115865e8b083SHaavard Skinnemoen 115965e8b083SHaavard Skinnemoen for_each_sg(data->sg, sg, data->sg_len, i) { 116065e8b083SHaavard Skinnemoen if (sg->offset & 3 || sg->length & 3) 1161796211b7SLudovic Desroches return atmci_prepare_data(host, data); 116265e8b083SHaavard Skinnemoen } 116365e8b083SHaavard Skinnemoen 116465e8b083SHaavard Skinnemoen /* If we don't have a channel, we can't do DMA */ 116565e8b083SHaavard Skinnemoen chan = host->dma.chan; 11666f49a57aSDan Williams if (chan) 116765e8b083SHaavard Skinnemoen host->data_chan = chan; 116865e8b083SHaavard Skinnemoen 116965e8b083SHaavard Skinnemoen if (!chan) 117065e8b083SHaavard Skinnemoen return -ENODEV; 117165e8b083SHaavard Skinnemoen 117205f5799cSVinod Koul if (data->flags & MMC_DATA_READ) { 1173e2b35f3dSViresh Kumar host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; 1174447dc0d2Sludovic.desroches@atmel.com maxburst = atmci_convert_chksize(host, 1175447dc0d2Sludovic.desroches@atmel.com host->dma_conf.src_maxburst); 117605f5799cSVinod Koul } else { 1177e2b35f3dSViresh Kumar host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; 1178447dc0d2Sludovic.desroches@atmel.com maxburst = atmci_convert_chksize(host, 1179447dc0d2Sludovic.desroches@atmel.com host->dma_conf.dst_maxburst); 118005f5799cSVinod Koul } 118165e8b083SHaavard Skinnemoen 1182ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) 1183ccdfe612SHein_Tibosch atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | 1184ccdfe612SHein_Tibosch ATMCI_DMAEN); 1185693e5e20SNicolas Ferre 1186266ac3f2SLinus Walleij sglen = dma_map_sg(chan->device->dev, data->sg, 1187feeef096SHeiner Kallweit data->sg_len, mmc_get_dma_dir(data)); 118888ce4db3SLinus Walleij 1189e2b35f3dSViresh Kumar dmaengine_slave_config(chan, &host->dma_conf); 119016052827SAlexandre Bounine desc = dmaengine_prep_slave_sg(chan, 119105f5799cSVinod Koul data->sg, sglen, slave_dirn, 119265e8b083SHaavard Skinnemoen DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 119365e8b083SHaavard Skinnemoen if (!desc) 1194657a77faSAtsushi Nemoto goto unmap_exit; 119565e8b083SHaavard Skinnemoen 119665e8b083SHaavard Skinnemoen host->dma.data_desc = desc; 119765e8b083SHaavard Skinnemoen desc->callback = atmci_dma_complete; 119865e8b083SHaavard Skinnemoen desc->callback_param = host; 119965e8b083SHaavard Skinnemoen 1200796211b7SLudovic Desroches return iflags; 1201657a77faSAtsushi Nemoto unmap_exit: 1202feeef096SHeiner Kallweit dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, 1203feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 1204657a77faSAtsushi Nemoto return -ENOMEM; 120565e8b083SHaavard Skinnemoen } 120665e8b083SHaavard Skinnemoen 1207796211b7SLudovic Desroches static void 1208796211b7SLudovic Desroches atmci_submit_data(struct atmel_mci *host, struct mmc_data *data) 1209796211b7SLudovic Desroches { 1210796211b7SLudovic Desroches return; 1211796211b7SLudovic Desroches } 1212796211b7SLudovic Desroches 1213796211b7SLudovic Desroches /* 1214796211b7SLudovic Desroches * Start PDC according to transfer direction. 1215796211b7SLudovic Desroches */ 1216796211b7SLudovic Desroches static void 1217796211b7SLudovic Desroches atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data) 1218796211b7SLudovic Desroches { 1219796211b7SLudovic Desroches if (data->flags & MMC_DATA_READ) 1220796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); 1221796211b7SLudovic Desroches else 1222796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); 1223796211b7SLudovic Desroches } 1224796211b7SLudovic Desroches 1225796211b7SLudovic Desroches static void 1226796211b7SLudovic Desroches atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) 122774791a2dSNicolas Ferre { 122874791a2dSNicolas Ferre struct dma_chan *chan = host->data_chan; 122974791a2dSNicolas Ferre struct dma_async_tx_descriptor *desc = host->dma.data_desc; 123074791a2dSNicolas Ferre 123174791a2dSNicolas Ferre if (chan) { 12325328906aSLinus Walleij dmaengine_submit(desc); 12335328906aSLinus Walleij dma_async_issue_pending(chan); 123474791a2dSNicolas Ferre } 123574791a2dSNicolas Ferre } 123674791a2dSNicolas Ferre 1237796211b7SLudovic Desroches static void atmci_stop_transfer(struct atmel_mci *host) 123865e8b083SHaavard Skinnemoen { 12396801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 12406801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 124165e8b083SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 124203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 124365e8b083SHaavard Skinnemoen } 124465e8b083SHaavard Skinnemoen 12457d2be074SHaavard Skinnemoen /* 12467122bbb0SMasanari Iida * Stop data transfer because error(s) occurred. 12477d2be074SHaavard Skinnemoen */ 1248796211b7SLudovic Desroches static void atmci_stop_transfer_pdc(struct atmel_mci *host) 12497d2be074SHaavard Skinnemoen { 1250f5177547SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); 1251796211b7SLudovic Desroches } 12527d2be074SHaavard Skinnemoen 1253796211b7SLudovic Desroches static void atmci_stop_transfer_dma(struct atmel_mci *host) 1254796211b7SLudovic Desroches { 1255796211b7SLudovic Desroches struct dma_chan *chan = host->data_chan; 12567d2be074SHaavard Skinnemoen 1257796211b7SLudovic Desroches if (chan) { 1258796211b7SLudovic Desroches dmaengine_terminate_all(chan); 1259796211b7SLudovic Desroches atmci_dma_cleanup(host); 1260796211b7SLudovic Desroches } else { 1261796211b7SLudovic Desroches /* Data transfer was stopped by the interrupt handler */ 12626801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 12636801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 1264796211b7SLudovic Desroches atmci_set_pending(host, EVENT_XFER_COMPLETE); 1265796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1266796211b7SLudovic Desroches } 1267796211b7SLudovic Desroches } 1268965ebf33SHaavard Skinnemoen 1269965ebf33SHaavard Skinnemoen /* 1270796211b7SLudovic Desroches * Start a request: prepare data if needed, prepare the command and activate 1271796211b7SLudovic Desroches * interrupts. 1272965ebf33SHaavard Skinnemoen */ 1273965ebf33SHaavard Skinnemoen static void atmci_start_request(struct atmel_mci *host, 1274965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot) 12757d2be074SHaavard Skinnemoen { 1276965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 12777d2be074SHaavard Skinnemoen struct mmc_command *cmd; 1278965ebf33SHaavard Skinnemoen struct mmc_data *data; 12797d2be074SHaavard Skinnemoen u32 iflags; 1280965ebf33SHaavard Skinnemoen u32 cmdflags; 1281965ebf33SHaavard Skinnemoen 1282965ebf33SHaavard Skinnemoen mrq = slot->mrq; 1283965ebf33SHaavard Skinnemoen host->cur_slot = slot; 1284965ebf33SHaavard Skinnemoen host->mrq = mrq; 1285965ebf33SHaavard Skinnemoen 1286965ebf33SHaavard Skinnemoen host->pending_events = 0; 1287965ebf33SHaavard Skinnemoen host->completed_events = 0; 1288f5177547SLudovic Desroches host->cmd_status = 0; 1289ca55f46eSHaavard Skinnemoen host->data_status = 0; 1290965ebf33SHaavard Skinnemoen 12916801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode); 12926801c41aSLudovic Desroches 129324011f34SLudovic Desroches if (host->need_reset || host->caps.need_reset_after_xfer) { 129418ee684bSLudovic Desroches iflags = atmci_readl(host, ATMCI_IMR); 129518ee684bSLudovic Desroches iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); 129603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 129703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 129803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1299796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 130003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 130118ee684bSLudovic Desroches atmci_writel(host, ATMCI_IER, iflags); 1302965ebf33SHaavard Skinnemoen host->need_reset = false; 1303965ebf33SHaavard Skinnemoen } 130403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); 13057d2be074SHaavard Skinnemoen 130603fc9a7fSLudovic Desroches iflags = atmci_readl(host, ATMCI_IMR); 13072c96a293SLudovic Desroches if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) 1308f5177547SLudovic Desroches dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", 1309965ebf33SHaavard Skinnemoen iflags); 13107d2be074SHaavard Skinnemoen 1311965ebf33SHaavard Skinnemoen if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { 1312965ebf33SHaavard Skinnemoen /* Send init sequence (74 clock cycles) */ 131303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); 131403fc9a7fSLudovic Desroches while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY)) 1315965ebf33SHaavard Skinnemoen cpu_relax(); 13167d2be074SHaavard Skinnemoen } 131774791a2dSNicolas Ferre iflags = 0; 13187d2be074SHaavard Skinnemoen data = mrq->data; 13197d2be074SHaavard Skinnemoen if (data) { 1320965ebf33SHaavard Skinnemoen atmci_set_timeout(host, slot, data); 1321a252e3e3SHaavard Skinnemoen 1322a252e3e3SHaavard Skinnemoen /* Must set block count/size before sending command */ 132303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) 13242c96a293SLudovic Desroches | ATMCI_BLKLEN(data->blksz)); 1325965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", 13262c96a293SLudovic Desroches ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); 132774791a2dSNicolas Ferre 1328796211b7SLudovic Desroches iflags |= host->prepare_data(host, data); 13297d2be074SHaavard Skinnemoen } 13307d2be074SHaavard Skinnemoen 13312c96a293SLudovic Desroches iflags |= ATMCI_CMDRDY; 13327d2be074SHaavard Skinnemoen cmd = mrq->cmd; 1333965ebf33SHaavard Skinnemoen cmdflags = atmci_prepare_command(slot->mmc, cmd); 133466b512edSLudovic Desroches 133566b512edSLudovic Desroches /* 133666b512edSLudovic Desroches * DMA transfer should be started before sending the command to avoid 133766b512edSLudovic Desroches * unexpected errors especially for read operations in SDIO mode. 133866b512edSLudovic Desroches * Unfortunately, in PDC mode, command has to be sent before starting 133966b512edSLudovic Desroches * the transfer. 134066b512edSLudovic Desroches */ 134166b512edSLudovic Desroches if (host->submit_data != &atmci_submit_data_dma) 134211d1488bSLudovic Desroches atmci_send_command(host, cmd, cmdflags); 13437d2be074SHaavard Skinnemoen 13447d2be074SHaavard Skinnemoen if (data) 1345796211b7SLudovic Desroches host->submit_data(host, data); 13467d2be074SHaavard Skinnemoen 134766b512edSLudovic Desroches if (host->submit_data == &atmci_submit_data_dma) 134866b512edSLudovic Desroches atmci_send_command(host, cmd, cmdflags); 134966b512edSLudovic Desroches 13507d2be074SHaavard Skinnemoen if (mrq->stop) { 1351965ebf33SHaavard Skinnemoen host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); 13522c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; 13537d2be074SHaavard Skinnemoen if (!(data->flags & MMC_DATA_WRITE)) 13542c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; 13552c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; 13567d2be074SHaavard Skinnemoen } 13577d2be074SHaavard Skinnemoen 13587d2be074SHaavard Skinnemoen /* 13597d2be074SHaavard Skinnemoen * We could have enabled interrupts earlier, but I suspect 13607d2be074SHaavard Skinnemoen * that would open up a nice can of interesting race 13617d2be074SHaavard Skinnemoen * conditions (e.g. command and data complete, but stop not 13627d2be074SHaavard Skinnemoen * prepared yet.) 13637d2be074SHaavard Skinnemoen */ 136403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, iflags); 136524011f34SLudovic Desroches 136624011f34SLudovic Desroches mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); 1367965ebf33SHaavard Skinnemoen } 13687d2be074SHaavard Skinnemoen 1369965ebf33SHaavard Skinnemoen static void atmci_queue_request(struct atmel_mci *host, 1370965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot, struct mmc_request *mrq) 1371965ebf33SHaavard Skinnemoen { 1372965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 1373965ebf33SHaavard Skinnemoen host->state); 1374965ebf33SHaavard Skinnemoen 1375965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1376965ebf33SHaavard Skinnemoen slot->mrq = mrq; 1377965ebf33SHaavard Skinnemoen if (host->state == STATE_IDLE) { 1378965ebf33SHaavard Skinnemoen host->state = STATE_SENDING_CMD; 1379965ebf33SHaavard Skinnemoen atmci_start_request(host, slot); 1380965ebf33SHaavard Skinnemoen } else { 13816801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "queue request\n"); 1382965ebf33SHaavard Skinnemoen list_add_tail(&slot->queue_node, &host->queue); 1383965ebf33SHaavard Skinnemoen } 1384965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1385965ebf33SHaavard Skinnemoen } 1386965ebf33SHaavard Skinnemoen 1387965ebf33SHaavard Skinnemoen static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1388965ebf33SHaavard Skinnemoen { 1389965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1390965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1391965ebf33SHaavard Skinnemoen struct mmc_data *data; 1392965ebf33SHaavard Skinnemoen 1393965ebf33SHaavard Skinnemoen WARN_ON(slot->mrq); 13946801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); 1395965ebf33SHaavard Skinnemoen 1396965ebf33SHaavard Skinnemoen /* 1397965ebf33SHaavard Skinnemoen * We may "know" the card is gone even though there's still an 1398965ebf33SHaavard Skinnemoen * electrical connection. If so, we really need to communicate 1399965ebf33SHaavard Skinnemoen * this to the MMC core since there won't be any more 1400965ebf33SHaavard Skinnemoen * interrupts as the card is completely removed. Otherwise, 1401965ebf33SHaavard Skinnemoen * the MMC core might believe the card is still there even 1402965ebf33SHaavard Skinnemoen * though the card was just removed very slowly. 1403965ebf33SHaavard Skinnemoen */ 1404965ebf33SHaavard Skinnemoen if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) { 1405965ebf33SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1406965ebf33SHaavard Skinnemoen mmc_request_done(mmc, mrq); 14077d2be074SHaavard Skinnemoen return; 1408965ebf33SHaavard Skinnemoen } 14097d2be074SHaavard Skinnemoen 1410965ebf33SHaavard Skinnemoen /* We don't support multiple blocks of weird lengths. */ 1411965ebf33SHaavard Skinnemoen data = mrq->data; 1412965ebf33SHaavard Skinnemoen if (data && data->blocks > 1 && data->blksz & 3) { 14137d2be074SHaavard Skinnemoen mrq->cmd->error = -EINVAL; 14147d2be074SHaavard Skinnemoen mmc_request_done(mmc, mrq); 14157d2be074SHaavard Skinnemoen } 14167d2be074SHaavard Skinnemoen 1417965ebf33SHaavard Skinnemoen atmci_queue_request(host, slot, mrq); 1418965ebf33SHaavard Skinnemoen } 1419965ebf33SHaavard Skinnemoen 14207d2be074SHaavard Skinnemoen static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 14217d2be074SHaavard Skinnemoen { 1422965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1423965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1424965ebf33SHaavard Skinnemoen unsigned int i; 1425ae552ab0SWenyou Yang 14262c96a293SLudovic Desroches slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; 1427945533b5SHaavard Skinnemoen switch (ios->bus_width) { 1428945533b5SHaavard Skinnemoen case MMC_BUS_WIDTH_1: 14292c96a293SLudovic Desroches slot->sdc_reg |= ATMCI_SDCBUS_1BIT; 1430945533b5SHaavard Skinnemoen break; 1431945533b5SHaavard Skinnemoen case MMC_BUS_WIDTH_4: 14322c96a293SLudovic Desroches slot->sdc_reg |= ATMCI_SDCBUS_4BIT; 1433945533b5SHaavard Skinnemoen break; 1434945533b5SHaavard Skinnemoen } 1435945533b5SHaavard Skinnemoen 14367d2be074SHaavard Skinnemoen if (ios->clock) { 1437965ebf33SHaavard Skinnemoen unsigned int clock_min = ~0U; 143860c8f783SLudovic Desroches int clkdiv; 14397d2be074SHaavard Skinnemoen 1440965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1441965ebf33SHaavard Skinnemoen if (!host->mode_reg) { 144203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 144303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 1444796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 144503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 1446965ebf33SHaavard Skinnemoen } 1447945533b5SHaavard Skinnemoen 1448965ebf33SHaavard Skinnemoen /* 1449965ebf33SHaavard Skinnemoen * Use mirror of ios->clock to prevent race with mmc 1450965ebf33SHaavard Skinnemoen * core ios update when finding the minimum. 1451965ebf33SHaavard Skinnemoen */ 1452965ebf33SHaavard Skinnemoen slot->clock = ios->clock; 14532c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 1454965ebf33SHaavard Skinnemoen if (host->slot[i] && host->slot[i]->clock 1455965ebf33SHaavard Skinnemoen && host->slot[i]->clock < clock_min) 1456965ebf33SHaavard Skinnemoen clock_min = host->slot[i]->clock; 1457965ebf33SHaavard Skinnemoen } 1458965ebf33SHaavard Skinnemoen 1459965ebf33SHaavard Skinnemoen /* Calculate clock divider */ 1460faf8180bSLudovic Desroches if (host->caps.has_odd_clk_div) { 1461faf8180bSLudovic Desroches clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; 146260c8f783SLudovic Desroches if (clkdiv < 0) { 146360c8f783SLudovic Desroches dev_warn(&mmc->class_dev, 146460c8f783SLudovic Desroches "clock %u too fast; using %lu\n", 146560c8f783SLudovic Desroches clock_min, host->bus_hz / 2); 146660c8f783SLudovic Desroches clkdiv = 0; 146760c8f783SLudovic Desroches } else if (clkdiv > 511) { 1468faf8180bSLudovic Desroches dev_warn(&mmc->class_dev, 1469faf8180bSLudovic Desroches "clock %u too slow; using %lu\n", 1470faf8180bSLudovic Desroches clock_min, host->bus_hz / (511 + 2)); 1471faf8180bSLudovic Desroches clkdiv = 511; 1472faf8180bSLudovic Desroches } 1473faf8180bSLudovic Desroches host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) 1474faf8180bSLudovic Desroches | ATMCI_MR_CLKODD(clkdiv & 1); 1475faf8180bSLudovic Desroches } else { 1476965ebf33SHaavard Skinnemoen clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; 14777d2be074SHaavard Skinnemoen if (clkdiv > 255) { 14787d2be074SHaavard Skinnemoen dev_warn(&mmc->class_dev, 14797d2be074SHaavard Skinnemoen "clock %u too slow; using %lu\n", 1480965ebf33SHaavard Skinnemoen clock_min, host->bus_hz / (2 * 256)); 14817d2be074SHaavard Skinnemoen clkdiv = 255; 14827d2be074SHaavard Skinnemoen } 14832c96a293SLudovic Desroches host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); 1484faf8180bSLudovic Desroches } 148504d699c3SRob Emanuele 1486965ebf33SHaavard Skinnemoen /* 1487965ebf33SHaavard Skinnemoen * WRPROOF and RDPROOF prevent overruns/underruns by 1488965ebf33SHaavard Skinnemoen * stopping the clock when the FIFO is full/empty. 1489965ebf33SHaavard Skinnemoen * This state is not expected to last for long. 1490965ebf33SHaavard Skinnemoen */ 1491796211b7SLudovic Desroches if (host->caps.has_rwproof) 14922c96a293SLudovic Desroches host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); 14937d2be074SHaavard Skinnemoen 1494796211b7SLudovic Desroches if (host->caps.has_cfg_reg) { 149599ddffd8SNicolas Ferre /* setup High Speed mode in relation with card capacity */ 149699ddffd8SNicolas Ferre if (ios->timing == MMC_TIMING_SD_HS) 14972c96a293SLudovic Desroches host->cfg_reg |= ATMCI_CFG_HSMODE; 1498965ebf33SHaavard Skinnemoen else 14992c96a293SLudovic Desroches host->cfg_reg &= ~ATMCI_CFG_HSMODE; 150099ddffd8SNicolas Ferre } 150199ddffd8SNicolas Ferre 150299ddffd8SNicolas Ferre if (list_empty(&host->queue)) { 150303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1504796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 150503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 150699ddffd8SNicolas Ferre } else { 1507965ebf33SHaavard Skinnemoen host->need_clock_update = true; 150899ddffd8SNicolas Ferre } 1509965ebf33SHaavard Skinnemoen 1510965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1511945533b5SHaavard Skinnemoen } else { 1512965ebf33SHaavard Skinnemoen bool any_slot_active = false; 1513965ebf33SHaavard Skinnemoen 1514965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1515965ebf33SHaavard Skinnemoen slot->clock = 0; 15162c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 1517965ebf33SHaavard Skinnemoen if (host->slot[i] && host->slot[i]->clock) { 1518965ebf33SHaavard Skinnemoen any_slot_active = true; 1519965ebf33SHaavard Skinnemoen break; 1520965ebf33SHaavard Skinnemoen } 1521965ebf33SHaavard Skinnemoen } 1522965ebf33SHaavard Skinnemoen if (!any_slot_active) { 152303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); 1524945533b5SHaavard Skinnemoen if (host->mode_reg) { 152503fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_MR); 1526945533b5SHaavard Skinnemoen } 1527945533b5SHaavard Skinnemoen host->mode_reg = 0; 15287d2be074SHaavard Skinnemoen } 1529965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1530965ebf33SHaavard Skinnemoen } 15317d2be074SHaavard Skinnemoen 15327d2be074SHaavard Skinnemoen switch (ios->power_mode) { 15339e7861f5SAlexandre Belloni case MMC_POWER_OFF: 15349e7861f5SAlexandre Belloni if (!IS_ERR(mmc->supply.vmmc)) 15359e7861f5SAlexandre Belloni mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 15369e7861f5SAlexandre Belloni break; 1537965ebf33SHaavard Skinnemoen case MMC_POWER_UP: 1538965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_NEED_INIT, &slot->flags); 15399e7861f5SAlexandre Belloni if (!IS_ERR(mmc->supply.vmmc)) 15409e7861f5SAlexandre Belloni mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); 1541965ebf33SHaavard Skinnemoen break; 15427d2be074SHaavard Skinnemoen default: 15437d2be074SHaavard Skinnemoen break; 15447d2be074SHaavard Skinnemoen } 15457d2be074SHaavard Skinnemoen } 15467d2be074SHaavard Skinnemoen 15477d2be074SHaavard Skinnemoen static int atmci_get_ro(struct mmc_host *mmc) 15487d2be074SHaavard Skinnemoen { 1549965ebf33SHaavard Skinnemoen int read_only = -ENOSYS; 1550965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 15517d2be074SHaavard Skinnemoen 1552965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->wp_pin)) { 1553965ebf33SHaavard Skinnemoen read_only = gpio_get_value(slot->wp_pin); 15547d2be074SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "card is %s\n", 15557d2be074SHaavard Skinnemoen read_only ? "read-only" : "read-write"); 15567d2be074SHaavard Skinnemoen } 15577d2be074SHaavard Skinnemoen 15587d2be074SHaavard Skinnemoen return read_only; 15597d2be074SHaavard Skinnemoen } 15607d2be074SHaavard Skinnemoen 1561965ebf33SHaavard Skinnemoen static int atmci_get_cd(struct mmc_host *mmc) 1562965ebf33SHaavard Skinnemoen { 1563965ebf33SHaavard Skinnemoen int present = -ENOSYS; 1564965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1565965ebf33SHaavard Skinnemoen 1566965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 15671c1452beSJonas Larsson present = !(gpio_get_value(slot->detect_pin) ^ 15681c1452beSJonas Larsson slot->detect_is_active_high); 1569965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "card is %spresent\n", 1570965ebf33SHaavard Skinnemoen present ? "" : "not "); 1571965ebf33SHaavard Skinnemoen } 1572965ebf33SHaavard Skinnemoen 1573965ebf33SHaavard Skinnemoen return present; 1574965ebf33SHaavard Skinnemoen } 1575965ebf33SHaavard Skinnemoen 157688ff82edSAnders Grahn static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) 157788ff82edSAnders Grahn { 157888ff82edSAnders Grahn struct atmel_mci_slot *slot = mmc_priv(mmc); 157988ff82edSAnders Grahn struct atmel_mci *host = slot->host; 158088ff82edSAnders Grahn 158188ff82edSAnders Grahn if (enable) 158203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, slot->sdio_irq); 158388ff82edSAnders Grahn else 158403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, slot->sdio_irq); 158588ff82edSAnders Grahn } 158688ff82edSAnders Grahn 1587965ebf33SHaavard Skinnemoen static const struct mmc_host_ops atmci_ops = { 15887d2be074SHaavard Skinnemoen .request = atmci_request, 15897d2be074SHaavard Skinnemoen .set_ios = atmci_set_ios, 15907d2be074SHaavard Skinnemoen .get_ro = atmci_get_ro, 1591965ebf33SHaavard Skinnemoen .get_cd = atmci_get_cd, 159288ff82edSAnders Grahn .enable_sdio_irq = atmci_enable_sdio_irq, 15937d2be074SHaavard Skinnemoen }; 15947d2be074SHaavard Skinnemoen 1595965ebf33SHaavard Skinnemoen /* Called with host->lock held */ 1596965ebf33SHaavard Skinnemoen static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) 1597965ebf33SHaavard Skinnemoen __releases(&host->lock) 1598965ebf33SHaavard Skinnemoen __acquires(&host->lock) 1599965ebf33SHaavard Skinnemoen { 1600965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = NULL; 1601965ebf33SHaavard Skinnemoen struct mmc_host *prev_mmc = host->cur_slot->mmc; 1602965ebf33SHaavard Skinnemoen 1603965ebf33SHaavard Skinnemoen WARN_ON(host->cmd || host->data); 1604965ebf33SHaavard Skinnemoen 1605965ebf33SHaavard Skinnemoen /* 1606965ebf33SHaavard Skinnemoen * Update the MMC clock rate if necessary. This may be 1607965ebf33SHaavard Skinnemoen * necessary if set_ios() is called when a different slot is 160825985edcSLucas De Marchi * busy transferring data. 1609965ebf33SHaavard Skinnemoen */ 161099ddffd8SNicolas Ferre if (host->need_clock_update) { 161103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1612796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 161303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 161499ddffd8SNicolas Ferre } 1615965ebf33SHaavard Skinnemoen 1616965ebf33SHaavard Skinnemoen host->cur_slot->mrq = NULL; 1617965ebf33SHaavard Skinnemoen host->mrq = NULL; 1618965ebf33SHaavard Skinnemoen if (!list_empty(&host->queue)) { 1619965ebf33SHaavard Skinnemoen slot = list_entry(host->queue.next, 1620965ebf33SHaavard Skinnemoen struct atmel_mci_slot, queue_node); 1621965ebf33SHaavard Skinnemoen list_del(&slot->queue_node); 1622965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", 1623965ebf33SHaavard Skinnemoen mmc_hostname(slot->mmc)); 1624965ebf33SHaavard Skinnemoen host->state = STATE_SENDING_CMD; 1625965ebf33SHaavard Skinnemoen atmci_start_request(host, slot); 1626965ebf33SHaavard Skinnemoen } else { 1627965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "list empty\n"); 1628965ebf33SHaavard Skinnemoen host->state = STATE_IDLE; 1629965ebf33SHaavard Skinnemoen } 1630965ebf33SHaavard Skinnemoen 163124011f34SLudovic Desroches del_timer(&host->timer); 163224011f34SLudovic Desroches 1633965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1634965ebf33SHaavard Skinnemoen mmc_request_done(prev_mmc, mrq); 1635965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1636965ebf33SHaavard Skinnemoen } 1637965ebf33SHaavard Skinnemoen 16387d2be074SHaavard Skinnemoen static void atmci_command_complete(struct atmel_mci *host, 1639c06ad258SHaavard Skinnemoen struct mmc_command *cmd) 16407d2be074SHaavard Skinnemoen { 1641c06ad258SHaavard Skinnemoen u32 status = host->cmd_status; 1642c06ad258SHaavard Skinnemoen 16437d2be074SHaavard Skinnemoen /* Read the response from the card (up to 16 bytes) */ 164403fc9a7fSLudovic Desroches cmd->resp[0] = atmci_readl(host, ATMCI_RSPR); 164503fc9a7fSLudovic Desroches cmd->resp[1] = atmci_readl(host, ATMCI_RSPR); 164603fc9a7fSLudovic Desroches cmd->resp[2] = atmci_readl(host, ATMCI_RSPR); 164703fc9a7fSLudovic Desroches cmd->resp[3] = atmci_readl(host, ATMCI_RSPR); 16487d2be074SHaavard Skinnemoen 16492c96a293SLudovic Desroches if (status & ATMCI_RTOE) 16507d2be074SHaavard Skinnemoen cmd->error = -ETIMEDOUT; 16512c96a293SLudovic Desroches else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE)) 16527d2be074SHaavard Skinnemoen cmd->error = -EILSEQ; 16532c96a293SLudovic Desroches else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) 16547d2be074SHaavard Skinnemoen cmd->error = -EIO; 165524011f34SLudovic Desroches else if (host->mrq->data && (host->mrq->data->blksz & 3)) { 165624011f34SLudovic Desroches if (host->caps.need_blksz_mul_4) { 165724011f34SLudovic Desroches cmd->error = -EINVAL; 165824011f34SLudovic Desroches host->need_reset = 1; 165924011f34SLudovic Desroches } 166024011f34SLudovic Desroches } else 16617d2be074SHaavard Skinnemoen cmd->error = 0; 16627d2be074SHaavard Skinnemoen } 16637d2be074SHaavard Skinnemoen 16642ee4f620SKees Cook static void atmci_detect_change(struct timer_list *t) 16657d2be074SHaavard Skinnemoen { 16662ee4f620SKees Cook struct atmel_mci_slot *slot = from_timer(slot, t, detect_timer); 1667965ebf33SHaavard Skinnemoen bool present; 1668965ebf33SHaavard Skinnemoen bool present_old; 16697d2be074SHaavard Skinnemoen 16707d2be074SHaavard Skinnemoen /* 1671965ebf33SHaavard Skinnemoen * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before 1672965ebf33SHaavard Skinnemoen * freeing the interrupt. We must not re-enable the interrupt 1673965ebf33SHaavard Skinnemoen * if it has been freed, and if we're shutting down, it 1674965ebf33SHaavard Skinnemoen * doesn't really matter whether the card is present or not. 16757d2be074SHaavard Skinnemoen */ 16767d2be074SHaavard Skinnemoen smp_rmb(); 1677965ebf33SHaavard Skinnemoen if (test_bit(ATMCI_SHUTDOWN, &slot->flags)) 16787d2be074SHaavard Skinnemoen return; 16797d2be074SHaavard Skinnemoen 1680965ebf33SHaavard Skinnemoen enable_irq(gpio_to_irq(slot->detect_pin)); 16811c1452beSJonas Larsson present = !(gpio_get_value(slot->detect_pin) ^ 16821c1452beSJonas Larsson slot->detect_is_active_high); 1683965ebf33SHaavard Skinnemoen present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags); 16847d2be074SHaavard Skinnemoen 1685965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n", 1686965ebf33SHaavard Skinnemoen present, present_old); 16877d2be074SHaavard Skinnemoen 1688965ebf33SHaavard Skinnemoen if (present != present_old) { 1689965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1690965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 1691965ebf33SHaavard Skinnemoen 1692965ebf33SHaavard Skinnemoen dev_dbg(&slot->mmc->class_dev, "card %s\n", 16937d2be074SHaavard Skinnemoen present ? "inserted" : "removed"); 16947d2be074SHaavard Skinnemoen 1695965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1696965ebf33SHaavard Skinnemoen 1697965ebf33SHaavard Skinnemoen if (!present) 1698965ebf33SHaavard Skinnemoen clear_bit(ATMCI_CARD_PRESENT, &slot->flags); 1699965ebf33SHaavard Skinnemoen else 1700965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_PRESENT, &slot->flags); 17017d2be074SHaavard Skinnemoen 17027d2be074SHaavard Skinnemoen /* Clean up queue if present */ 1703965ebf33SHaavard Skinnemoen mrq = slot->mrq; 17047d2be074SHaavard Skinnemoen if (mrq) { 1705965ebf33SHaavard Skinnemoen if (mrq == host->mrq) { 17067d2be074SHaavard Skinnemoen /* 17077d2be074SHaavard Skinnemoen * Reset controller to terminate any ongoing 17087d2be074SHaavard Skinnemoen * commands or data transfers. 17097d2be074SHaavard Skinnemoen */ 171003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 171103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 171203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1713796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 171403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 17157d2be074SHaavard Skinnemoen 17167d2be074SHaavard Skinnemoen host->data = NULL; 17177d2be074SHaavard Skinnemoen host->cmd = NULL; 1718c06ad258SHaavard Skinnemoen 1719c06ad258SHaavard Skinnemoen switch (host->state) { 1720965ebf33SHaavard Skinnemoen case STATE_IDLE: 1721965ebf33SHaavard Skinnemoen break; 1722c06ad258SHaavard Skinnemoen case STATE_SENDING_CMD: 1723c06ad258SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1724f5177547SLudovic Desroches if (mrq->data) 1725f5177547SLudovic Desroches host->stop_transfer(host); 1726c06ad258SHaavard Skinnemoen break; 1727f5177547SLudovic Desroches case STATE_DATA_XFER: 1728c06ad258SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1729796211b7SLudovic Desroches host->stop_transfer(host); 1730c06ad258SHaavard Skinnemoen break; 1731f5177547SLudovic Desroches case STATE_WAITING_NOTBUSY: 1732c06ad258SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1733c06ad258SHaavard Skinnemoen break; 1734c06ad258SHaavard Skinnemoen case STATE_SENDING_STOP: 1735c06ad258SHaavard Skinnemoen mrq->stop->error = -ENOMEDIUM; 1736c06ad258SHaavard Skinnemoen break; 1737f5177547SLudovic Desroches case STATE_END_REQUEST: 1738f5177547SLudovic Desroches break; 1739c06ad258SHaavard Skinnemoen } 1740c06ad258SHaavard Skinnemoen 1741965ebf33SHaavard Skinnemoen atmci_request_end(host, mrq); 1742965ebf33SHaavard Skinnemoen } else { 1743965ebf33SHaavard Skinnemoen list_del(&slot->queue_node); 1744965ebf33SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1745965ebf33SHaavard Skinnemoen if (mrq->data) 1746965ebf33SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1747965ebf33SHaavard Skinnemoen if (mrq->stop) 1748965ebf33SHaavard Skinnemoen mrq->stop->error = -ENOMEDIUM; 17497d2be074SHaavard Skinnemoen 1750965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1751965ebf33SHaavard Skinnemoen mmc_request_done(slot->mmc, mrq); 1752965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1753965ebf33SHaavard Skinnemoen } 1754965ebf33SHaavard Skinnemoen } 1755965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1756965ebf33SHaavard Skinnemoen 1757965ebf33SHaavard Skinnemoen mmc_detect_change(slot->mmc, 0); 17587d2be074SHaavard Skinnemoen } 17597d2be074SHaavard Skinnemoen } 17607d2be074SHaavard Skinnemoen 17617d2be074SHaavard Skinnemoen static void atmci_tasklet_func(unsigned long priv) 17627d2be074SHaavard Skinnemoen { 1763965ebf33SHaavard Skinnemoen struct atmel_mci *host = (struct atmel_mci *)priv; 17647d2be074SHaavard Skinnemoen struct mmc_request *mrq = host->mrq; 17657d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 1766c06ad258SHaavard Skinnemoen enum atmel_mci_state state = host->state; 1767c06ad258SHaavard Skinnemoen enum atmel_mci_state prev_state; 1768c06ad258SHaavard Skinnemoen u32 status; 1769c06ad258SHaavard Skinnemoen 1770965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1771965ebf33SHaavard Skinnemoen 1772c06ad258SHaavard Skinnemoen state = host->state; 17737d2be074SHaavard Skinnemoen 1774965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, 1775c06ad258SHaavard Skinnemoen "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", 1776c06ad258SHaavard Skinnemoen state, host->pending_events, host->completed_events, 177703fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_IMR)); 17787d2be074SHaavard Skinnemoen 1779c06ad258SHaavard Skinnemoen do { 1780c06ad258SHaavard Skinnemoen prev_state = state; 17816801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state); 1782c06ad258SHaavard Skinnemoen 1783c06ad258SHaavard Skinnemoen switch (state) { 1784965ebf33SHaavard Skinnemoen case STATE_IDLE: 1785965ebf33SHaavard Skinnemoen break; 1786965ebf33SHaavard Skinnemoen 1787c06ad258SHaavard Skinnemoen case STATE_SENDING_CMD: 1788f5177547SLudovic Desroches /* 1789f5177547SLudovic Desroches * Command has been sent, we are waiting for command 1790f5177547SLudovic Desroches * ready. Then we have three next states possible: 1791f5177547SLudovic Desroches * END_REQUEST by default, WAITING_NOTBUSY if it's a 1792f5177547SLudovic Desroches * command needing it or DATA_XFER if there is data. 1793f5177547SLudovic Desroches */ 17946801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); 1795c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1796f5177547SLudovic Desroches EVENT_CMD_RDY)) 1797c06ad258SHaavard Skinnemoen break; 1798c06ad258SHaavard Skinnemoen 17996801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed cmd ready\n"); 18007d2be074SHaavard Skinnemoen host->cmd = NULL; 1801f5177547SLudovic Desroches atmci_set_completed(host, EVENT_CMD_RDY); 1802c06ad258SHaavard Skinnemoen atmci_command_complete(host, mrq->cmd); 1803f5177547SLudovic Desroches if (mrq->data) { 18046801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 18056801c41aSLudovic Desroches "command with data transfer"); 1806f5177547SLudovic Desroches /* 1807f5177547SLudovic Desroches * If there is a command error don't start 1808f5177547SLudovic Desroches * data transfer. 1809f5177547SLudovic Desroches */ 1810f5177547SLudovic Desroches if (mrq->cmd->error) { 1811f5177547SLudovic Desroches host->stop_transfer(host); 1812f5177547SLudovic Desroches host->data = NULL; 1813f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, 1814f5177547SLudovic Desroches ATMCI_TXRDY | ATMCI_RXRDY 1815f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1816f5177547SLudovic Desroches state = STATE_END_REQUEST; 1817f5177547SLudovic Desroches } else 1818f5177547SLudovic Desroches state = STATE_DATA_XFER; 1819f5177547SLudovic Desroches } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { 18206801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 18216801c41aSLudovic Desroches "command response need waiting notbusy"); 1822f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1823f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1824f5177547SLudovic Desroches } else 1825f5177547SLudovic Desroches state = STATE_END_REQUEST; 1826c06ad258SHaavard Skinnemoen 1827f5177547SLudovic Desroches break; 1828c06ad258SHaavard Skinnemoen 1829f5177547SLudovic Desroches case STATE_DATA_XFER: 1830c06ad258SHaavard Skinnemoen if (atmci_test_and_clear_pending(host, 1831c06ad258SHaavard Skinnemoen EVENT_DATA_ERROR)) { 18326801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed data error\n"); 1833f5177547SLudovic Desroches atmci_set_completed(host, EVENT_DATA_ERROR); 1834f5177547SLudovic Desroches state = STATE_END_REQUEST; 1835c06ad258SHaavard Skinnemoen break; 18367d2be074SHaavard Skinnemoen } 18377d2be074SHaavard Skinnemoen 1838f5177547SLudovic Desroches /* 1839f5177547SLudovic Desroches * A data transfer is in progress. The event expected 1840f5177547SLudovic Desroches * to move to the next state depends of data transfer 1841f5177547SLudovic Desroches * type (PDC or DMA). Once transfer done we can move 1842f5177547SLudovic Desroches * to the next step which is WAITING_NOTBUSY in write 1843f5177547SLudovic Desroches * case and directly SENDING_STOP in read case. 1844f5177547SLudovic Desroches */ 18456801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n"); 1846c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1847c06ad258SHaavard Skinnemoen EVENT_XFER_COMPLETE)) 1848c06ad258SHaavard Skinnemoen break; 18497d2be074SHaavard Skinnemoen 18506801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 18516801c41aSLudovic Desroches "(%s) set completed xfer complete\n", 18526801c41aSLudovic Desroches __func__); 1853c06ad258SHaavard Skinnemoen atmci_set_completed(host, EVENT_XFER_COMPLETE); 1854c06ad258SHaavard Skinnemoen 1855077d4073SLudovic Desroches if (host->caps.need_notbusy_for_read_ops || 1856077d4073SLudovic Desroches (host->data->flags & MMC_DATA_WRITE)) { 1857f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1858f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1859f5177547SLudovic Desroches } else if (host->mrq->stop) { 1860f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); 1861f5177547SLudovic Desroches atmci_send_stop_cmd(host, data); 1862f5177547SLudovic Desroches state = STATE_SENDING_STOP; 1863f5177547SLudovic Desroches } else { 1864c06ad258SHaavard Skinnemoen host->data = NULL; 18657d2be074SHaavard Skinnemoen data->bytes_xfered = data->blocks * data->blksz; 18667d2be074SHaavard Skinnemoen data->error = 0; 1867f5177547SLudovic Desroches state = STATE_END_REQUEST; 18687d2be074SHaavard Skinnemoen } 1869f5177547SLudovic Desroches break; 18707d2be074SHaavard Skinnemoen 1871f5177547SLudovic Desroches case STATE_WAITING_NOTBUSY: 1872f5177547SLudovic Desroches /* 1873f5177547SLudovic Desroches * We can be in the state for two reasons: a command 1874f5177547SLudovic Desroches * requiring waiting not busy signal (stop command 1875f5177547SLudovic Desroches * included) or a write operation. In the latest case, 1876f5177547SLudovic Desroches * we need to send a stop command. 1877f5177547SLudovic Desroches */ 18786801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: not busy?\n"); 1879f5177547SLudovic Desroches if (!atmci_test_and_clear_pending(host, 1880f5177547SLudovic Desroches EVENT_NOTBUSY)) 1881f5177547SLudovic Desroches break; 18827d2be074SHaavard Skinnemoen 18836801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed not busy\n"); 1884f5177547SLudovic Desroches atmci_set_completed(host, EVENT_NOTBUSY); 1885f5177547SLudovic Desroches 1886f5177547SLudovic Desroches if (host->data) { 1887f5177547SLudovic Desroches /* 1888f5177547SLudovic Desroches * For some commands such as CMD53, even if 1889f5177547SLudovic Desroches * there is data transfer, there is no stop 1890f5177547SLudovic Desroches * command to send. 1891f5177547SLudovic Desroches */ 1892f5177547SLudovic Desroches if (host->mrq->stop) { 1893f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, 1894f5177547SLudovic Desroches ATMCI_CMDRDY); 18952c96a293SLudovic Desroches atmci_send_stop_cmd(host, data); 1896f5177547SLudovic Desroches state = STATE_SENDING_STOP; 1897f5177547SLudovic Desroches } else { 1898f5177547SLudovic Desroches host->data = NULL; 1899f5177547SLudovic Desroches data->bytes_xfered = data->blocks 1900f5177547SLudovic Desroches * data->blksz; 1901f5177547SLudovic Desroches data->error = 0; 1902f5177547SLudovic Desroches state = STATE_END_REQUEST; 1903f5177547SLudovic Desroches } 1904f5177547SLudovic Desroches } else 1905f5177547SLudovic Desroches state = STATE_END_REQUEST; 1906f5177547SLudovic Desroches break; 1907c06ad258SHaavard Skinnemoen 1908c06ad258SHaavard Skinnemoen case STATE_SENDING_STOP: 1909f5177547SLudovic Desroches /* 1910f5177547SLudovic Desroches * In this state, it is important to set host->data to 1911f5177547SLudovic Desroches * NULL (which is tested in the waiting notbusy state) 1912f5177547SLudovic Desroches * in order to go to the end request state instead of 1913f5177547SLudovic Desroches * sending stop again. 1914f5177547SLudovic Desroches */ 19156801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); 1916c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1917f5177547SLudovic Desroches EVENT_CMD_RDY)) 1918c06ad258SHaavard Skinnemoen break; 1919c06ad258SHaavard Skinnemoen 19206801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); 1921c06ad258SHaavard Skinnemoen host->cmd = NULL; 1922f5177547SLudovic Desroches data->bytes_xfered = data->blocks * data->blksz; 1923f5177547SLudovic Desroches data->error = 0; 1924c06ad258SHaavard Skinnemoen atmci_command_complete(host, mrq->stop); 1925f5177547SLudovic Desroches if (mrq->stop->error) { 1926f5177547SLudovic Desroches host->stop_transfer(host); 1927f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, 1928f5177547SLudovic Desroches ATMCI_TXRDY | ATMCI_RXRDY 1929f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1930f5177547SLudovic Desroches state = STATE_END_REQUEST; 1931f5177547SLudovic Desroches } else { 1932f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1933f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1934f5177547SLudovic Desroches } 193541b4e9a1SNicolas Ferre host->data = NULL; 1936c06ad258SHaavard Skinnemoen break; 1937c06ad258SHaavard Skinnemoen 1938f5177547SLudovic Desroches case STATE_END_REQUEST: 1939f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY 1940f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1941f5177547SLudovic Desroches status = host->data_status; 1942f5177547SLudovic Desroches if (unlikely(status)) { 1943f5177547SLudovic Desroches host->stop_transfer(host); 1944f5177547SLudovic Desroches host->data = NULL; 1945fbd986cdSRodolfo Giometti if (data) { 1946f5177547SLudovic Desroches if (status & ATMCI_DTOE) { 1947f5177547SLudovic Desroches data->error = -ETIMEDOUT; 1948f5177547SLudovic Desroches } else if (status & ATMCI_DCRCE) { 1949f5177547SLudovic Desroches data->error = -EILSEQ; 1950f5177547SLudovic Desroches } else { 1951f5177547SLudovic Desroches data->error = -EIO; 1952f5177547SLudovic Desroches } 1953f5177547SLudovic Desroches } 1954fbd986cdSRodolfo Giometti } 1955f5177547SLudovic Desroches 1956f5177547SLudovic Desroches atmci_request_end(host, host->mrq); 1957f5177547SLudovic Desroches state = STATE_IDLE; 1958c06ad258SHaavard Skinnemoen break; 1959c06ad258SHaavard Skinnemoen } 1960c06ad258SHaavard Skinnemoen } while (state != prev_state); 1961c06ad258SHaavard Skinnemoen 1962c06ad258SHaavard Skinnemoen host->state = state; 1963965ebf33SHaavard Skinnemoen 1964965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 19657d2be074SHaavard Skinnemoen } 19667d2be074SHaavard Skinnemoen 19677d2be074SHaavard Skinnemoen static void atmci_read_data_pio(struct atmel_mci *host) 19687d2be074SHaavard Skinnemoen { 19697d2be074SHaavard Skinnemoen struct scatterlist *sg = host->sg; 19707d2be074SHaavard Skinnemoen unsigned int offset = host->pio_offset; 19717d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 19727d2be074SHaavard Skinnemoen u32 value; 19737d2be074SHaavard Skinnemoen u32 status; 19747d2be074SHaavard Skinnemoen unsigned int nbytes = 0; 19757d2be074SHaavard Skinnemoen 19767d2be074SHaavard Skinnemoen do { 197703fc9a7fSLudovic Desroches value = atmci_readl(host, ATMCI_RDR); 19787d2be074SHaavard Skinnemoen if (likely(offset + 4 <= sg->length)) { 19795b427781SChristoph Hellwig sg_pcopy_to_buffer(sg, 1, &value, sizeof(u32), offset); 19807d2be074SHaavard Skinnemoen 19817d2be074SHaavard Skinnemoen offset += 4; 19827d2be074SHaavard Skinnemoen nbytes += 4; 19837d2be074SHaavard Skinnemoen 19847d2be074SHaavard Skinnemoen if (offset == sg->length) { 19855e7184aeSHaavard Skinnemoen flush_dcache_page(sg_page(sg)); 19867d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 1987bdbc5d0cSTerry Barnaby host->sg_len--; 1988bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) 19897d2be074SHaavard Skinnemoen goto done; 19907d2be074SHaavard Skinnemoen 19917d2be074SHaavard Skinnemoen offset = 0; 19927d2be074SHaavard Skinnemoen } 19937d2be074SHaavard Skinnemoen } else { 19947d2be074SHaavard Skinnemoen unsigned int remaining = sg->length - offset; 19955b427781SChristoph Hellwig 19965b427781SChristoph Hellwig sg_pcopy_to_buffer(sg, 1, &value, remaining, offset); 19977d2be074SHaavard Skinnemoen nbytes += remaining; 19987d2be074SHaavard Skinnemoen 19997d2be074SHaavard Skinnemoen flush_dcache_page(sg_page(sg)); 20007d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 2001bdbc5d0cSTerry Barnaby host->sg_len--; 2002bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) 20037d2be074SHaavard Skinnemoen goto done; 20047d2be074SHaavard Skinnemoen 20057d2be074SHaavard Skinnemoen offset = 4 - remaining; 20065b427781SChristoph Hellwig sg_pcopy_to_buffer(sg, 1, (u8 *)&value + remaining, 20075b427781SChristoph Hellwig offset, 0); 20087d2be074SHaavard Skinnemoen nbytes += offset; 20097d2be074SHaavard Skinnemoen } 20107d2be074SHaavard Skinnemoen 201103fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 20127d2be074SHaavard Skinnemoen if (status & ATMCI_DATA_ERROR_FLAGS) { 201303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY 20147d2be074SHaavard Skinnemoen | ATMCI_DATA_ERROR_FLAGS)); 20157d2be074SHaavard Skinnemoen host->data_status = status; 2016965ebf33SHaavard Skinnemoen data->bytes_xfered += nbytes; 2017965ebf33SHaavard Skinnemoen return; 20187d2be074SHaavard Skinnemoen } 20192c96a293SLudovic Desroches } while (status & ATMCI_RXRDY); 20207d2be074SHaavard Skinnemoen 20217d2be074SHaavard Skinnemoen host->pio_offset = offset; 20227d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 20237d2be074SHaavard Skinnemoen 20247d2be074SHaavard Skinnemoen return; 20257d2be074SHaavard Skinnemoen 20267d2be074SHaavard Skinnemoen done: 202703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY); 202803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 20297d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 2030965ebf33SHaavard Skinnemoen smp_wmb(); 2031c06ad258SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 20327d2be074SHaavard Skinnemoen } 20337d2be074SHaavard Skinnemoen 20347d2be074SHaavard Skinnemoen static void atmci_write_data_pio(struct atmel_mci *host) 20357d2be074SHaavard Skinnemoen { 20367d2be074SHaavard Skinnemoen struct scatterlist *sg = host->sg; 20377d2be074SHaavard Skinnemoen unsigned int offset = host->pio_offset; 20387d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 20397d2be074SHaavard Skinnemoen u32 value; 20407d2be074SHaavard Skinnemoen u32 status; 20417d2be074SHaavard Skinnemoen unsigned int nbytes = 0; 20427d2be074SHaavard Skinnemoen 20437d2be074SHaavard Skinnemoen do { 20447d2be074SHaavard Skinnemoen if (likely(offset + 4 <= sg->length)) { 20455b427781SChristoph Hellwig sg_pcopy_from_buffer(sg, 1, &value, sizeof(u32), offset); 204603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20477d2be074SHaavard Skinnemoen 20487d2be074SHaavard Skinnemoen offset += 4; 20497d2be074SHaavard Skinnemoen nbytes += 4; 20507d2be074SHaavard Skinnemoen if (offset == sg->length) { 20517d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 2052bdbc5d0cSTerry Barnaby host->sg_len--; 2053bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) 20547d2be074SHaavard Skinnemoen goto done; 20557d2be074SHaavard Skinnemoen 20567d2be074SHaavard Skinnemoen offset = 0; 20577d2be074SHaavard Skinnemoen } 20587d2be074SHaavard Skinnemoen } else { 20597d2be074SHaavard Skinnemoen unsigned int remaining = sg->length - offset; 20607d2be074SHaavard Skinnemoen 20617d2be074SHaavard Skinnemoen value = 0; 20625b427781SChristoph Hellwig sg_pcopy_from_buffer(sg, 1, &value, remaining, offset); 20637d2be074SHaavard Skinnemoen nbytes += remaining; 20647d2be074SHaavard Skinnemoen 20657d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 2066bdbc5d0cSTerry Barnaby host->sg_len--; 2067bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) { 206803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20697d2be074SHaavard Skinnemoen goto done; 20707d2be074SHaavard Skinnemoen } 20717d2be074SHaavard Skinnemoen 20727d2be074SHaavard Skinnemoen offset = 4 - remaining; 20735b427781SChristoph Hellwig sg_pcopy_from_buffer(sg, 1, (u8 *)&value + remaining, 20745b427781SChristoph Hellwig offset, 0); 207503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20767d2be074SHaavard Skinnemoen nbytes += offset; 20777d2be074SHaavard Skinnemoen } 20787d2be074SHaavard Skinnemoen 207903fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 20807d2be074SHaavard Skinnemoen if (status & ATMCI_DATA_ERROR_FLAGS) { 208103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY 20827d2be074SHaavard Skinnemoen | ATMCI_DATA_ERROR_FLAGS)); 20837d2be074SHaavard Skinnemoen host->data_status = status; 2084965ebf33SHaavard Skinnemoen data->bytes_xfered += nbytes; 2085965ebf33SHaavard Skinnemoen return; 20867d2be074SHaavard Skinnemoen } 20872c96a293SLudovic Desroches } while (status & ATMCI_TXRDY); 20887d2be074SHaavard Skinnemoen 20897d2be074SHaavard Skinnemoen host->pio_offset = offset; 20907d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 20917d2be074SHaavard Skinnemoen 20927d2be074SHaavard Skinnemoen return; 20937d2be074SHaavard Skinnemoen 20947d2be074SHaavard Skinnemoen done: 209503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY); 209603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 20977d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 2098965ebf33SHaavard Skinnemoen smp_wmb(); 2099c06ad258SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 21007d2be074SHaavard Skinnemoen } 21017d2be074SHaavard Skinnemoen 210288ff82edSAnders Grahn static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) 210388ff82edSAnders Grahn { 210488ff82edSAnders Grahn int i; 210588ff82edSAnders Grahn 21062c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 210788ff82edSAnders Grahn struct atmel_mci_slot *slot = host->slot[i]; 210888ff82edSAnders Grahn if (slot && (status & slot->sdio_irq)) { 210988ff82edSAnders Grahn mmc_signal_sdio_irq(slot->mmc); 211088ff82edSAnders Grahn } 211188ff82edSAnders Grahn } 211288ff82edSAnders Grahn } 211388ff82edSAnders Grahn 211488ff82edSAnders Grahn 21157d2be074SHaavard Skinnemoen static irqreturn_t atmci_interrupt(int irq, void *dev_id) 21167d2be074SHaavard Skinnemoen { 2117965ebf33SHaavard Skinnemoen struct atmel_mci *host = dev_id; 21187d2be074SHaavard Skinnemoen u32 status, mask, pending; 21197d2be074SHaavard Skinnemoen unsigned int pass_count = 0; 21207d2be074SHaavard Skinnemoen 21217d2be074SHaavard Skinnemoen do { 212203fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 212303fc9a7fSLudovic Desroches mask = atmci_readl(host, ATMCI_IMR); 21247d2be074SHaavard Skinnemoen pending = status & mask; 21257d2be074SHaavard Skinnemoen if (!pending) 21267d2be074SHaavard Skinnemoen break; 21277d2be074SHaavard Skinnemoen 21287d2be074SHaavard Skinnemoen if (pending & ATMCI_DATA_ERROR_FLAGS) { 21296801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: data error\n"); 213003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS 2131f5177547SLudovic Desroches | ATMCI_RXRDY | ATMCI_TXRDY 2132f5177547SLudovic Desroches | ATMCI_ENDRX | ATMCI_ENDTX 2133f5177547SLudovic Desroches | ATMCI_RXBUFF | ATMCI_TXBUFE); 2134965ebf33SHaavard Skinnemoen 21357d2be074SHaavard Skinnemoen host->data_status = status; 21366801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending data error\n"); 2137965ebf33SHaavard Skinnemoen smp_wmb(); 21387d2be074SHaavard Skinnemoen atmci_set_pending(host, EVENT_DATA_ERROR); 21397d2be074SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 21407d2be074SHaavard Skinnemoen } 2141796211b7SLudovic Desroches 2142796211b7SLudovic Desroches if (pending & ATMCI_TXBUFE) { 21436801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n"); 2144796211b7SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); 21457e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); 2146796211b7SLudovic Desroches /* 2147796211b7SLudovic Desroches * We can receive this interruption before having configured 2148796211b7SLudovic Desroches * the second pdc buffer, so we need to reconfigure first and 2149796211b7SLudovic Desroches * second buffers again 2150796211b7SLudovic Desroches */ 2151796211b7SLudovic Desroches if (host->data_size) { 2152796211b7SLudovic Desroches atmci_pdc_set_both_buf(host, XFER_TRANSMIT); 21537e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); 2154796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); 2155796211b7SLudovic Desroches } else { 2156796211b7SLudovic Desroches atmci_pdc_complete(host); 2157796211b7SLudovic Desroches } 21587e8ba228SLudovic Desroches } else if (pending & ATMCI_ENDTX) { 21596801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n"); 21607e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); 21617e8ba228SLudovic Desroches 21627e8ba228SLudovic Desroches if (host->data_size) { 21637e8ba228SLudovic Desroches atmci_pdc_set_single_buf(host, 21647e8ba228SLudovic Desroches XFER_TRANSMIT, PDC_SECOND_BUF); 21657e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); 21667e8ba228SLudovic Desroches } 2167796211b7SLudovic Desroches } 2168796211b7SLudovic Desroches 21697e8ba228SLudovic Desroches if (pending & ATMCI_RXBUFF) { 21706801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n"); 21717e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); 21727e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); 21737e8ba228SLudovic Desroches /* 21747e8ba228SLudovic Desroches * We can receive this interruption before having configured 21757e8ba228SLudovic Desroches * the second pdc buffer, so we need to reconfigure first and 21767e8ba228SLudovic Desroches * second buffers again 21777e8ba228SLudovic Desroches */ 21787e8ba228SLudovic Desroches if (host->data_size) { 21797e8ba228SLudovic Desroches atmci_pdc_set_both_buf(host, XFER_RECEIVE); 21807e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); 21817e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); 21827e8ba228SLudovic Desroches } else { 21837e8ba228SLudovic Desroches atmci_pdc_complete(host); 21847e8ba228SLudovic Desroches } 21857e8ba228SLudovic Desroches } else if (pending & ATMCI_ENDRX) { 21866801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n"); 2187796211b7SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); 2188796211b7SLudovic Desroches 2189796211b7SLudovic Desroches if (host->data_size) { 2190796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, 2191796211b7SLudovic Desroches XFER_RECEIVE, PDC_SECOND_BUF); 2192796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); 2193796211b7SLudovic Desroches } 2194796211b7SLudovic Desroches } 2195796211b7SLudovic Desroches 2196f5177547SLudovic Desroches /* 2197f5177547SLudovic Desroches * First mci IPs, so mainly the ones having pdc, have some 2198f5177547SLudovic Desroches * issues with the notbusy signal. You can't get it after 2199f5177547SLudovic Desroches * data transmission if you have not sent a stop command. 2200f5177547SLudovic Desroches * The appropriate workaround is to use the BLKE signal. 2201f5177547SLudovic Desroches */ 2202f5177547SLudovic Desroches if (pending & ATMCI_BLKE) { 22036801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: blke\n"); 2204f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_BLKE); 2205965ebf33SHaavard Skinnemoen smp_wmb(); 22066801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending notbusy\n"); 2207f5177547SLudovic Desroches atmci_set_pending(host, EVENT_NOTBUSY); 22087d2be074SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 22097d2be074SHaavard Skinnemoen } 2210f5177547SLudovic Desroches 2211f5177547SLudovic Desroches if (pending & ATMCI_NOTBUSY) { 22126801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); 2213f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); 2214f5177547SLudovic Desroches smp_wmb(); 22156801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending notbusy\n"); 2216f5177547SLudovic Desroches atmci_set_pending(host, EVENT_NOTBUSY); 2217f5177547SLudovic Desroches tasklet_schedule(&host->tasklet); 2218f5177547SLudovic Desroches } 2219f5177547SLudovic Desroches 22202c96a293SLudovic Desroches if (pending & ATMCI_RXRDY) 22217d2be074SHaavard Skinnemoen atmci_read_data_pio(host); 22222c96a293SLudovic Desroches if (pending & ATMCI_TXRDY) 22237d2be074SHaavard Skinnemoen atmci_write_data_pio(host); 22247d2be074SHaavard Skinnemoen 2225f5177547SLudovic Desroches if (pending & ATMCI_CMDRDY) { 22266801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n"); 2227f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); 2228f5177547SLudovic Desroches host->cmd_status = status; 2229f5177547SLudovic Desroches smp_wmb(); 22306801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending cmd rdy\n"); 2231f5177547SLudovic Desroches atmci_set_pending(host, EVENT_CMD_RDY); 2232f5177547SLudovic Desroches tasklet_schedule(&host->tasklet); 2233f5177547SLudovic Desroches } 223488ff82edSAnders Grahn 22352c96a293SLudovic Desroches if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) 223688ff82edSAnders Grahn atmci_sdio_interrupt(host, status); 223788ff82edSAnders Grahn 22387d2be074SHaavard Skinnemoen } while (pass_count++ < 5); 22397d2be074SHaavard Skinnemoen 22407d2be074SHaavard Skinnemoen return pass_count ? IRQ_HANDLED : IRQ_NONE; 22417d2be074SHaavard Skinnemoen } 22427d2be074SHaavard Skinnemoen 22437d2be074SHaavard Skinnemoen static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) 22447d2be074SHaavard Skinnemoen { 2245965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = dev_id; 22467d2be074SHaavard Skinnemoen 22477d2be074SHaavard Skinnemoen /* 22487d2be074SHaavard Skinnemoen * Disable interrupts until the pin has stabilized and check 22497d2be074SHaavard Skinnemoen * the state then. Use mod_timer() since we may be in the 22507d2be074SHaavard Skinnemoen * middle of the timer routine when this interrupt triggers. 22517d2be074SHaavard Skinnemoen */ 22527d2be074SHaavard Skinnemoen disable_irq_nosync(irq); 2253965ebf33SHaavard Skinnemoen mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20)); 22547d2be074SHaavard Skinnemoen 22557d2be074SHaavard Skinnemoen return IRQ_HANDLED; 22567d2be074SHaavard Skinnemoen } 22577d2be074SHaavard Skinnemoen 2258ab050b92Sludovic.desroches@atmel.com static int atmci_init_slot(struct atmel_mci *host, 2259965ebf33SHaavard Skinnemoen struct mci_slot_pdata *slot_data, unsigned int id, 226088ff82edSAnders Grahn u32 sdc_reg, u32 sdio_irq) 2261965ebf33SHaavard Skinnemoen { 2262965ebf33SHaavard Skinnemoen struct mmc_host *mmc; 2263965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot; 2264965ebf33SHaavard Skinnemoen 2265965ebf33SHaavard Skinnemoen mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev); 2266965ebf33SHaavard Skinnemoen if (!mmc) 2267965ebf33SHaavard Skinnemoen return -ENOMEM; 2268965ebf33SHaavard Skinnemoen 2269965ebf33SHaavard Skinnemoen slot = mmc_priv(mmc); 2270965ebf33SHaavard Skinnemoen slot->mmc = mmc; 2271965ebf33SHaavard Skinnemoen slot->host = host; 2272965ebf33SHaavard Skinnemoen slot->detect_pin = slot_data->detect_pin; 2273965ebf33SHaavard Skinnemoen slot->wp_pin = slot_data->wp_pin; 22741c1452beSJonas Larsson slot->detect_is_active_high = slot_data->detect_is_active_high; 2275965ebf33SHaavard Skinnemoen slot->sdc_reg = sdc_reg; 227688ff82edSAnders Grahn slot->sdio_irq = sdio_irq; 2277965ebf33SHaavard Skinnemoen 2278e919fd20SLudovic Desroches dev_dbg(&mmc->class_dev, 2279e919fd20SLudovic Desroches "slot[%u]: bus_width=%u, detect_pin=%d, " 2280e919fd20SLudovic Desroches "detect_is_active_high=%s, wp_pin=%d\n", 2281e919fd20SLudovic Desroches id, slot_data->bus_width, slot_data->detect_pin, 2282e919fd20SLudovic Desroches slot_data->detect_is_active_high ? "true" : "false", 2283e919fd20SLudovic Desroches slot_data->wp_pin); 2284e919fd20SLudovic Desroches 2285965ebf33SHaavard Skinnemoen mmc->ops = &atmci_ops; 2286965ebf33SHaavard Skinnemoen mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); 2287965ebf33SHaavard Skinnemoen mmc->f_max = host->bus_hz / 2; 2288965ebf33SHaavard Skinnemoen mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 228988ff82edSAnders Grahn if (sdio_irq) 229088ff82edSAnders Grahn mmc->caps |= MMC_CAP_SDIO_IRQ; 2291796211b7SLudovic Desroches if (host->caps.has_highspeed) 229299ddffd8SNicolas Ferre mmc->caps |= MMC_CAP_SD_HIGHSPEED; 22937a90dcc2SLudovic Desroches /* 22947a90dcc2SLudovic Desroches * Without the read/write proof capability, it is strongly suggested to 22957a90dcc2SLudovic Desroches * use only one bit for data to prevent fifo underruns and overruns 22967a90dcc2SLudovic Desroches * which will corrupt data. 22977a90dcc2SLudovic Desroches */ 22987a90dcc2SLudovic Desroches if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) 2299965ebf33SHaavard Skinnemoen mmc->caps |= MMC_CAP_4_BIT_DATA; 2300965ebf33SHaavard Skinnemoen 23017a90dcc2SLudovic Desroches if (atmci_get_version(host) < 0x200) { 23027a90dcc2SLudovic Desroches mmc->max_segs = 256; 23037a90dcc2SLudovic Desroches mmc->max_blk_size = 4095; 23047a90dcc2SLudovic Desroches mmc->max_blk_count = 256; 23057a90dcc2SLudovic Desroches mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 23067a90dcc2SLudovic Desroches mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs; 23077a90dcc2SLudovic Desroches } else { 2308a36274e0SMartin K. Petersen mmc->max_segs = 64; 2309965ebf33SHaavard Skinnemoen mmc->max_req_size = 32768 * 512; 2310965ebf33SHaavard Skinnemoen mmc->max_blk_size = 32768; 2311965ebf33SHaavard Skinnemoen mmc->max_blk_count = 512; 23127a90dcc2SLudovic Desroches } 2313965ebf33SHaavard Skinnemoen 2314965ebf33SHaavard Skinnemoen /* Assume card is present initially */ 2315965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_PRESENT, &slot->flags); 2316965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 23177bca646eSPramod Gurav if (devm_gpio_request(&host->pdev->dev, slot->detect_pin, 23187bca646eSPramod Gurav "mmc_detect")) { 2319965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "no detect pin available\n"); 2320965ebf33SHaavard Skinnemoen slot->detect_pin = -EBUSY; 23211c1452beSJonas Larsson } else if (gpio_get_value(slot->detect_pin) ^ 23221c1452beSJonas Larsson slot->detect_is_active_high) { 2323965ebf33SHaavard Skinnemoen clear_bit(ATMCI_CARD_PRESENT, &slot->flags); 2324965ebf33SHaavard Skinnemoen } 2325965ebf33SHaavard Skinnemoen } 2326965ebf33SHaavard Skinnemoen 232776d55564STimo Kokkonen if (!gpio_is_valid(slot->detect_pin)) { 232876d55564STimo Kokkonen if (slot_data->non_removable) 232976d55564STimo Kokkonen mmc->caps |= MMC_CAP_NONREMOVABLE; 233076d55564STimo Kokkonen else 2331965ebf33SHaavard Skinnemoen mmc->caps |= MMC_CAP_NEEDS_POLL; 233276d55564STimo Kokkonen } 2333965ebf33SHaavard Skinnemoen 2334965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->wp_pin)) { 23357bca646eSPramod Gurav if (devm_gpio_request(&host->pdev->dev, slot->wp_pin, 23367bca646eSPramod Gurav "mmc_wp")) { 2337965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "no WP pin available\n"); 2338965ebf33SHaavard Skinnemoen slot->wp_pin = -EBUSY; 2339965ebf33SHaavard Skinnemoen } 2340965ebf33SHaavard Skinnemoen } 2341965ebf33SHaavard Skinnemoen 2342965ebf33SHaavard Skinnemoen host->slot[id] = slot; 23439e7861f5SAlexandre Belloni mmc_regulator_get_supply(mmc); 2344965ebf33SHaavard Skinnemoen mmc_add_host(mmc); 2345965ebf33SHaavard Skinnemoen 2346965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 2347965ebf33SHaavard Skinnemoen int ret; 2348965ebf33SHaavard Skinnemoen 23492ee4f620SKees Cook timer_setup(&slot->detect_timer, atmci_detect_change, 0); 2350965ebf33SHaavard Skinnemoen 2351965ebf33SHaavard Skinnemoen ret = request_irq(gpio_to_irq(slot->detect_pin), 2352965ebf33SHaavard Skinnemoen atmci_detect_interrupt, 2353965ebf33SHaavard Skinnemoen IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 2354965ebf33SHaavard Skinnemoen "mmc-detect", slot); 2355965ebf33SHaavard Skinnemoen if (ret) { 2356965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, 2357965ebf33SHaavard Skinnemoen "could not request IRQ %d for detect pin\n", 2358965ebf33SHaavard Skinnemoen gpio_to_irq(slot->detect_pin)); 2359965ebf33SHaavard Skinnemoen slot->detect_pin = -EBUSY; 2360965ebf33SHaavard Skinnemoen } 2361965ebf33SHaavard Skinnemoen } 2362965ebf33SHaavard Skinnemoen 2363965ebf33SHaavard Skinnemoen atmci_init_debugfs(slot); 2364965ebf33SHaavard Skinnemoen 2365965ebf33SHaavard Skinnemoen return 0; 2366965ebf33SHaavard Skinnemoen } 2367965ebf33SHaavard Skinnemoen 23685fef365bSArnd Bergmann static void atmci_cleanup_slot(struct atmel_mci_slot *slot, 2369965ebf33SHaavard Skinnemoen unsigned int id) 2370965ebf33SHaavard Skinnemoen { 2371965ebf33SHaavard Skinnemoen /* Debugfs stuff is cleaned up by mmc core */ 2372965ebf33SHaavard Skinnemoen 2373965ebf33SHaavard Skinnemoen set_bit(ATMCI_SHUTDOWN, &slot->flags); 2374965ebf33SHaavard Skinnemoen smp_wmb(); 2375965ebf33SHaavard Skinnemoen 2376965ebf33SHaavard Skinnemoen mmc_remove_host(slot->mmc); 2377965ebf33SHaavard Skinnemoen 2378965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 2379965ebf33SHaavard Skinnemoen int pin = slot->detect_pin; 2380965ebf33SHaavard Skinnemoen 2381965ebf33SHaavard Skinnemoen free_irq(gpio_to_irq(pin), slot); 2382965ebf33SHaavard Skinnemoen del_timer_sync(&slot->detect_timer); 2383965ebf33SHaavard Skinnemoen } 2384965ebf33SHaavard Skinnemoen 2385965ebf33SHaavard Skinnemoen slot->host->slot[id] = NULL; 2386965ebf33SHaavard Skinnemoen mmc_free_host(slot->mmc); 2387965ebf33SHaavard Skinnemoen } 2388965ebf33SHaavard Skinnemoen 2389467e081dSludovic.desroches@atmel.com static int atmci_configure_dma(struct atmel_mci *host) 23902635d1baSNicolas Ferre { 2391467e081dSludovic.desroches@atmel.com host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev, 2392467e081dSludovic.desroches@atmel.com "rxtx"); 239374843787SMans Rullgard 239474843787SMans Rullgard if (PTR_ERR(host->dma.chan) == -ENODEV) { 239574843787SMans Rullgard struct mci_platform_data *pdata = host->pdev->dev.platform_data; 239674843787SMans Rullgard dma_cap_mask_t mask; 239774843787SMans Rullgard 239893c77d29SBrent Taylor if (!pdata || !pdata->dma_filter) 239974843787SMans Rullgard return -ENODEV; 240074843787SMans Rullgard 240174843787SMans Rullgard dma_cap_zero(mask); 240274843787SMans Rullgard dma_cap_set(DMA_SLAVE, mask); 240374843787SMans Rullgard 240474843787SMans Rullgard host->dma.chan = dma_request_channel(mask, pdata->dma_filter, 240574843787SMans Rullgard pdata->dma_slave); 240674843787SMans Rullgard if (!host->dma.chan) 240774843787SMans Rullgard host->dma.chan = ERR_PTR(-ENODEV); 240874843787SMans Rullgard } 240974843787SMans Rullgard 2410467e081dSludovic.desroches@atmel.com if (IS_ERR(host->dma.chan)) 2411467e081dSludovic.desroches@atmel.com return PTR_ERR(host->dma.chan); 24122635d1baSNicolas Ferre 2413467e081dSludovic.desroches@atmel.com dev_info(&host->pdev->dev, "using %s for DMA transfers\n", 241474791a2dSNicolas Ferre dma_chan_name(host->dma.chan)); 2415e2b35f3dSViresh Kumar 2416e2b35f3dSViresh Kumar host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; 2417e2b35f3dSViresh Kumar host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 2418e2b35f3dSViresh Kumar host->dma_conf.src_maxburst = 1; 2419e2b35f3dSViresh Kumar host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; 2420e2b35f3dSViresh Kumar host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 2421e2b35f3dSViresh Kumar host->dma_conf.dst_maxburst = 1; 2422e2b35f3dSViresh Kumar host->dma_conf.device_fc = false; 2423467e081dSludovic.desroches@atmel.com 2424467e081dSludovic.desroches@atmel.com return 0; 24252635d1baSNicolas Ferre } 2426796211b7SLudovic Desroches 2427796211b7SLudovic Desroches /* 2428796211b7SLudovic Desroches * HSMCI (High Speed MCI) module is not fully compatible with MCI module. 2429796211b7SLudovic Desroches * HSMCI provides DMA support and a new config register but no more supports 2430796211b7SLudovic Desroches * PDC. 2431796211b7SLudovic Desroches */ 2432ab050b92Sludovic.desroches@atmel.com static void atmci_get_cap(struct atmel_mci *host) 2433796211b7SLudovic Desroches { 2434796211b7SLudovic Desroches unsigned int version; 2435796211b7SLudovic Desroches 2436796211b7SLudovic Desroches version = atmci_get_version(host); 2437796211b7SLudovic Desroches dev_info(&host->pdev->dev, 2438796211b7SLudovic Desroches "version: 0x%x\n", version); 2439796211b7SLudovic Desroches 2440ccdfe612SHein_Tibosch host->caps.has_dma_conf_reg = 0; 2441ef4b160fSAndy Shevchenko host->caps.has_pdc = 1; 2442796211b7SLudovic Desroches host->caps.has_cfg_reg = 0; 2443796211b7SLudovic Desroches host->caps.has_cstor_reg = 0; 2444796211b7SLudovic Desroches host->caps.has_highspeed = 0; 2445796211b7SLudovic Desroches host->caps.has_rwproof = 0; 2446faf8180bSLudovic Desroches host->caps.has_odd_clk_div = 0; 244724011f34SLudovic Desroches host->caps.has_bad_data_ordering = 1; 244824011f34SLudovic Desroches host->caps.need_reset_after_xfer = 1; 244924011f34SLudovic Desroches host->caps.need_blksz_mul_4 = 1; 2450077d4073SLudovic Desroches host->caps.need_notbusy_for_read_ops = 0; 2451796211b7SLudovic Desroches 2452796211b7SLudovic Desroches /* keep only major version number */ 2453796211b7SLudovic Desroches switch (version & 0xf00) { 2454215ba399SNicolas Ferre case 0x600: 2455796211b7SLudovic Desroches case 0x500: 2456faf8180bSLudovic Desroches host->caps.has_odd_clk_div = 1; 2457faf8180bSLudovic Desroches case 0x400: 2458faf8180bSLudovic Desroches case 0x300: 2459ccdfe612SHein_Tibosch host->caps.has_dma_conf_reg = 1; 2460faf8180bSLudovic Desroches host->caps.has_pdc = 0; 2461796211b7SLudovic Desroches host->caps.has_cfg_reg = 1; 2462796211b7SLudovic Desroches host->caps.has_cstor_reg = 1; 2463796211b7SLudovic Desroches host->caps.has_highspeed = 1; 2464faf8180bSLudovic Desroches case 0x200: 2465796211b7SLudovic Desroches host->caps.has_rwproof = 1; 246624011f34SLudovic Desroches host->caps.need_blksz_mul_4 = 0; 2467077d4073SLudovic Desroches host->caps.need_notbusy_for_read_ops = 1; 2468faf8180bSLudovic Desroches case 0x100: 246924011f34SLudovic Desroches host->caps.has_bad_data_ordering = 0; 247024011f34SLudovic Desroches host->caps.need_reset_after_xfer = 0; 247124011f34SLudovic Desroches case 0x0: 2472796211b7SLudovic Desroches break; 2473796211b7SLudovic Desroches default: 2474faf8180bSLudovic Desroches host->caps.has_pdc = 0; 2475796211b7SLudovic Desroches dev_warn(&host->pdev->dev, 2476796211b7SLudovic Desroches "Unmanaged mci version, set minimum capabilities\n"); 2477796211b7SLudovic Desroches break; 2478796211b7SLudovic Desroches } 2479796211b7SLudovic Desroches } 248074465b4fSDan Williams 2481ab050b92Sludovic.desroches@atmel.com static int atmci_probe(struct platform_device *pdev) 24827d2be074SHaavard Skinnemoen { 24837d2be074SHaavard Skinnemoen struct mci_platform_data *pdata; 24847d2be074SHaavard Skinnemoen struct atmel_mci *host; 24857d2be074SHaavard Skinnemoen struct resource *regs; 2486965ebf33SHaavard Skinnemoen unsigned int nr_slots; 24877d2be074SHaavard Skinnemoen int irq; 2488528bc780SPramod Gurav int ret, i; 24897d2be074SHaavard Skinnemoen 24907d2be074SHaavard Skinnemoen regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 24917d2be074SHaavard Skinnemoen if (!regs) 24927d2be074SHaavard Skinnemoen return -ENXIO; 24937d2be074SHaavard Skinnemoen pdata = pdev->dev.platform_data; 2494e919fd20SLudovic Desroches if (!pdata) { 2495e919fd20SLudovic Desroches pdata = atmci_of_init(pdev); 2496e919fd20SLudovic Desroches if (IS_ERR(pdata)) { 2497e919fd20SLudovic Desroches dev_err(&pdev->dev, "platform data not available\n"); 2498e919fd20SLudovic Desroches return PTR_ERR(pdata); 2499e919fd20SLudovic Desroches } 2500e919fd20SLudovic Desroches } 2501e919fd20SLudovic Desroches 25027d2be074SHaavard Skinnemoen irq = platform_get_irq(pdev, 0); 25037d2be074SHaavard Skinnemoen if (irq < 0) 25047d2be074SHaavard Skinnemoen return irq; 25057d2be074SHaavard Skinnemoen 25067bca646eSPramod Gurav host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); 2507965ebf33SHaavard Skinnemoen if (!host) 25087d2be074SHaavard Skinnemoen return -ENOMEM; 25097d2be074SHaavard Skinnemoen 25107d2be074SHaavard Skinnemoen host->pdev = pdev; 2511965ebf33SHaavard Skinnemoen spin_lock_init(&host->lock); 2512965ebf33SHaavard Skinnemoen INIT_LIST_HEAD(&host->queue); 25137d2be074SHaavard Skinnemoen 25147bca646eSPramod Gurav host->mck = devm_clk_get(&pdev->dev, "mci_clk"); 25157bca646eSPramod Gurav if (IS_ERR(host->mck)) 25167bca646eSPramod Gurav return PTR_ERR(host->mck); 25177d2be074SHaavard Skinnemoen 25187bca646eSPramod Gurav host->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); 25197d2be074SHaavard Skinnemoen if (!host->regs) 25207bca646eSPramod Gurav return -ENOMEM; 25217d2be074SHaavard Skinnemoen 2522b3894f26SBoris BREZILLON ret = clk_prepare_enable(host->mck); 2523b3894f26SBoris BREZILLON if (ret) 25247bca646eSPramod Gurav return ret; 25257bca646eSPramod Gurav 252603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 25277d2be074SHaavard Skinnemoen host->bus_hz = clk_get_rate(host->mck); 25287d2be074SHaavard Skinnemoen 25297d2be074SHaavard Skinnemoen host->mapbase = regs->start; 25307d2be074SHaavard Skinnemoen 2531965ebf33SHaavard Skinnemoen tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host); 25327d2be074SHaavard Skinnemoen 253389c8aa20SKay Sievers ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); 2534ae552ab0SWenyou Yang if (ret) { 2535ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 25367bca646eSPramod Gurav return ret; 2537ae552ab0SWenyou Yang } 25387d2be074SHaavard Skinnemoen 2539796211b7SLudovic Desroches /* Get MCI capabilities and set operations according to it */ 2540796211b7SLudovic Desroches atmci_get_cap(host); 2541467e081dSludovic.desroches@atmel.com ret = atmci_configure_dma(host); 2542467e081dSludovic.desroches@atmel.com if (ret == -EPROBE_DEFER) 2543467e081dSludovic.desroches@atmel.com goto err_dma_probe_defer; 2544467e081dSludovic.desroches@atmel.com if (ret == 0) { 2545796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data_dma; 2546796211b7SLudovic Desroches host->submit_data = &atmci_submit_data_dma; 2547796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer_dma; 2548796211b7SLudovic Desroches } else if (host->caps.has_pdc) { 2549796211b7SLudovic Desroches dev_info(&pdev->dev, "using PDC\n"); 2550796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data_pdc; 2551796211b7SLudovic Desroches host->submit_data = &atmci_submit_data_pdc; 2552796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer_pdc; 2553796211b7SLudovic Desroches } else { 2554ef878198SLudovic Desroches dev_info(&pdev->dev, "using PIO\n"); 2555796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data; 2556796211b7SLudovic Desroches host->submit_data = &atmci_submit_data; 2557796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer; 2558796211b7SLudovic Desroches } 2559796211b7SLudovic Desroches 25607d2be074SHaavard Skinnemoen platform_set_drvdata(pdev, host); 25617d2be074SHaavard Skinnemoen 25622ee4f620SKees Cook timer_setup(&host->timer, atmci_timeout_timer, 0); 2563b87cc1b5SLudovic Desroches 2564ae552ab0SWenyou Yang pm_runtime_get_noresume(&pdev->dev); 2565ae552ab0SWenyou Yang pm_runtime_set_active(&pdev->dev); 2566ae552ab0SWenyou Yang pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY); 2567ae552ab0SWenyou Yang pm_runtime_use_autosuspend(&pdev->dev); 2568ae552ab0SWenyou Yang pm_runtime_enable(&pdev->dev); 2569ae552ab0SWenyou Yang 2570965ebf33SHaavard Skinnemoen /* We need at least one slot to succeed */ 2571965ebf33SHaavard Skinnemoen nr_slots = 0; 2572965ebf33SHaavard Skinnemoen ret = -ENODEV; 2573965ebf33SHaavard Skinnemoen if (pdata->slot[0].bus_width) { 2574965ebf33SHaavard Skinnemoen ret = atmci_init_slot(host, &pdata->slot[0], 25752c96a293SLudovic Desroches 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); 25767a90dcc2SLudovic Desroches if (!ret) { 2577965ebf33SHaavard Skinnemoen nr_slots++; 25787a90dcc2SLudovic Desroches host->buf_size = host->slot[0]->mmc->max_req_size; 25797a90dcc2SLudovic Desroches } 25807d2be074SHaavard Skinnemoen } 2581965ebf33SHaavard Skinnemoen if (pdata->slot[1].bus_width) { 2582965ebf33SHaavard Skinnemoen ret = atmci_init_slot(host, &pdata->slot[1], 25832c96a293SLudovic Desroches 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); 25847a90dcc2SLudovic Desroches if (!ret) { 2585965ebf33SHaavard Skinnemoen nr_slots++; 25867a90dcc2SLudovic Desroches if (host->slot[1]->mmc->max_req_size > host->buf_size) 25877a90dcc2SLudovic Desroches host->buf_size = 25887a90dcc2SLudovic Desroches host->slot[1]->mmc->max_req_size; 25897a90dcc2SLudovic Desroches } 25907d2be074SHaavard Skinnemoen } 25917d2be074SHaavard Skinnemoen 259204d699c3SRob Emanuele if (!nr_slots) { 259304d699c3SRob Emanuele dev_err(&pdev->dev, "init failed: no slot defined\n"); 2594965ebf33SHaavard Skinnemoen goto err_init_slot; 259504d699c3SRob Emanuele } 25967d2be074SHaavard Skinnemoen 25977a90dcc2SLudovic Desroches if (!host->caps.has_rwproof) { 25987a90dcc2SLudovic Desroches host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, 25997a90dcc2SLudovic Desroches &host->buf_phys_addr, 26007a90dcc2SLudovic Desroches GFP_KERNEL); 26017a90dcc2SLudovic Desroches if (!host->buffer) { 26027a90dcc2SLudovic Desroches ret = -ENOMEM; 26037a90dcc2SLudovic Desroches dev_err(&pdev->dev, "buffer allocation failed\n"); 2604528bc780SPramod Gurav goto err_dma_alloc; 26057a90dcc2SLudovic Desroches } 26067a90dcc2SLudovic Desroches } 26077a90dcc2SLudovic Desroches 2608965ebf33SHaavard Skinnemoen dev_info(&pdev->dev, 2609965ebf33SHaavard Skinnemoen "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", 2610965ebf33SHaavard Skinnemoen host->mapbase, irq, nr_slots); 2611deec9ae3SHaavard Skinnemoen 2612ae552ab0SWenyou Yang pm_runtime_mark_last_busy(&host->pdev->dev); 2613ae552ab0SWenyou Yang pm_runtime_put_autosuspend(&pdev->dev); 2614ae552ab0SWenyou Yang 26157d2be074SHaavard Skinnemoen return 0; 26167d2be074SHaavard Skinnemoen 2617528bc780SPramod Gurav err_dma_alloc: 2618528bc780SPramod Gurav for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 2619528bc780SPramod Gurav if (host->slot[i]) 2620528bc780SPramod Gurav atmci_cleanup_slot(host->slot[i], i); 2621528bc780SPramod Gurav } 2622965ebf33SHaavard Skinnemoen err_init_slot: 2623ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2624ae552ab0SWenyou Yang 2625ae552ab0SWenyou Yang pm_runtime_disable(&pdev->dev); 2626ae552ab0SWenyou Yang pm_runtime_put_noidle(&pdev->dev); 2627ae552ab0SWenyou Yang 2628528bc780SPramod Gurav del_timer_sync(&host->timer); 2629467e081dSludovic.desroches@atmel.com if (!IS_ERR(host->dma.chan)) 263074465b4fSDan Williams dma_release_channel(host->dma.chan); 2631467e081dSludovic.desroches@atmel.com err_dma_probe_defer: 2632965ebf33SHaavard Skinnemoen free_irq(irq, host); 26337d2be074SHaavard Skinnemoen return ret; 26347d2be074SHaavard Skinnemoen } 26357d2be074SHaavard Skinnemoen 2636ab050b92Sludovic.desroches@atmel.com static int atmci_remove(struct platform_device *pdev) 26377d2be074SHaavard Skinnemoen { 26387d2be074SHaavard Skinnemoen struct atmel_mci *host = platform_get_drvdata(pdev); 2639965ebf33SHaavard Skinnemoen unsigned int i; 26407d2be074SHaavard Skinnemoen 2641ae552ab0SWenyou Yang pm_runtime_get_sync(&pdev->dev); 2642ae552ab0SWenyou Yang 26437a90dcc2SLudovic Desroches if (host->buffer) 26447a90dcc2SLudovic Desroches dma_free_coherent(&pdev->dev, host->buf_size, 26457a90dcc2SLudovic Desroches host->buffer, host->buf_phys_addr); 26467a90dcc2SLudovic Desroches 26472c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 2648965ebf33SHaavard Skinnemoen if (host->slot[i]) 2649965ebf33SHaavard Skinnemoen atmci_cleanup_slot(host->slot[i], i); 26507d2be074SHaavard Skinnemoen } 26517d2be074SHaavard Skinnemoen 265203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ~0UL); 265303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); 265403fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_SR); 26557d2be074SHaavard Skinnemoen 2656528bc780SPramod Gurav del_timer_sync(&host->timer); 2657467e081dSludovic.desroches@atmel.com if (!IS_ERR(host->dma.chan)) 265874465b4fSDan Williams dma_release_channel(host->dma.chan); 265965e8b083SHaavard Skinnemoen 2660965ebf33SHaavard Skinnemoen free_irq(platform_get_irq(pdev, 0), host); 26617d2be074SHaavard Skinnemoen 2662ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2663ae552ab0SWenyou Yang 2664ae552ab0SWenyou Yang pm_runtime_disable(&pdev->dev); 2665ae552ab0SWenyou Yang pm_runtime_put_noidle(&pdev->dev); 2666ae552ab0SWenyou Yang 26677d2be074SHaavard Skinnemoen return 0; 26687d2be074SHaavard Skinnemoen } 26697d2be074SHaavard Skinnemoen 2670ae552ab0SWenyou Yang #ifdef CONFIG_PM 2671ae552ab0SWenyou Yang static int atmci_runtime_suspend(struct device *dev) 2672ae552ab0SWenyou Yang { 2673ae552ab0SWenyou Yang struct atmel_mci *host = dev_get_drvdata(dev); 2674ae552ab0SWenyou Yang 2675ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2676ae552ab0SWenyou Yang 2677b5b64fa6SWenyou Yang pinctrl_pm_select_sleep_state(dev); 2678b5b64fa6SWenyou Yang 2679ae552ab0SWenyou Yang return 0; 2680ae552ab0SWenyou Yang } 2681ae552ab0SWenyou Yang 2682ae552ab0SWenyou Yang static int atmci_runtime_resume(struct device *dev) 2683ae552ab0SWenyou Yang { 2684ae552ab0SWenyou Yang struct atmel_mci *host = dev_get_drvdata(dev); 2685ae552ab0SWenyou Yang 2686b5b64fa6SWenyou Yang pinctrl_pm_select_default_state(dev); 2687b5b64fa6SWenyou Yang 2688ae552ab0SWenyou Yang return clk_prepare_enable(host->mck); 2689ae552ab0SWenyou Yang } 2690ae552ab0SWenyou Yang #endif 2691ae552ab0SWenyou Yang 2692ae552ab0SWenyou Yang static const struct dev_pm_ops atmci_dev_pm_ops = { 2693ae552ab0SWenyou Yang SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 2694ae552ab0SWenyou Yang pm_runtime_force_resume) 2695c3cb6ba4SLudovic Desroches SET_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL) 2696ae552ab0SWenyou Yang }; 2697ae552ab0SWenyou Yang 26987d2be074SHaavard Skinnemoen static struct platform_driver atmci_driver = { 26995e0fe897Sludovic.desroches@atmel.com .probe = atmci_probe, 2700ab050b92Sludovic.desroches@atmel.com .remove = atmci_remove, 27017d2be074SHaavard Skinnemoen .driver = { 27027d2be074SHaavard Skinnemoen .name = "atmel_mci", 2703e919fd20SLudovic Desroches .of_match_table = of_match_ptr(atmci_dt_ids), 2704ae552ab0SWenyou Yang .pm = &atmci_dev_pm_ops, 27057d2be074SHaavard Skinnemoen }, 27067d2be074SHaavard Skinnemoen }; 27075e0fe897Sludovic.desroches@atmel.com module_platform_driver(atmci_driver); 27087d2be074SHaavard Skinnemoen 27097d2be074SHaavard Skinnemoen MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); 2710e05503efSJean Delvare MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); 27117d2be074SHaavard Skinnemoen MODULE_LICENSE("GPL v2"); 2712