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)) { 668e919fd20SLudovic Desroches dev_warn(&pdev->dev, "reg property is missing for %s\n", 669e919fd20SLudovic Desroches cnp->full_name); 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); 676e919fd20SLudovic Desroches break; 677e919fd20SLudovic Desroches } 678e919fd20SLudovic Desroches 679e919fd20SLudovic Desroches if (of_property_read_u32(cnp, "bus-width", 680e919fd20SLudovic Desroches &pdata->slot[slot_id].bus_width)) 681e919fd20SLudovic Desroches pdata->slot[slot_id].bus_width = 1; 682e919fd20SLudovic Desroches 683e919fd20SLudovic Desroches pdata->slot[slot_id].detect_pin = 684e919fd20SLudovic Desroches of_get_named_gpio(cnp, "cd-gpios", 0); 685e919fd20SLudovic Desroches 686e919fd20SLudovic Desroches pdata->slot[slot_id].detect_is_active_high = 687e919fd20SLudovic Desroches of_property_read_bool(cnp, "cd-inverted"); 688e919fd20SLudovic Desroches 68976d55564STimo Kokkonen pdata->slot[slot_id].non_removable = 69076d55564STimo Kokkonen of_property_read_bool(cnp, "non-removable"); 69176d55564STimo Kokkonen 692e919fd20SLudovic Desroches pdata->slot[slot_id].wp_pin = 693e919fd20SLudovic Desroches of_get_named_gpio(cnp, "wp-gpios", 0); 694e919fd20SLudovic Desroches } 695e919fd20SLudovic Desroches 696e919fd20SLudovic Desroches return pdata; 697e919fd20SLudovic Desroches } 698e919fd20SLudovic Desroches #else /* CONFIG_OF */ 699e919fd20SLudovic Desroches static inline struct mci_platform_data* 700e919fd20SLudovic Desroches atmci_of_init(struct platform_device *dev) 701e919fd20SLudovic Desroches { 702e919fd20SLudovic Desroches return ERR_PTR(-EINVAL); 703e919fd20SLudovic Desroches } 704e919fd20SLudovic Desroches #endif 705e919fd20SLudovic Desroches 7067a90dcc2SLudovic Desroches static inline unsigned int atmci_get_version(struct atmel_mci *host) 7077a90dcc2SLudovic Desroches { 7087a90dcc2SLudovic Desroches return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; 7097a90dcc2SLudovic Desroches } 7107a90dcc2SLudovic Desroches 711447dc0d2Sludovic.desroches@atmel.com /* 712447dc0d2Sludovic.desroches@atmel.com * Fix sconfig's burst size according to atmel MCI. We need to convert them as: 713447dc0d2Sludovic.desroches@atmel.com * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. 714447dc0d2Sludovic.desroches@atmel.com * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2, 715447dc0d2Sludovic.desroches@atmel.com * 8 -> 3, 16 -> 4. 716447dc0d2Sludovic.desroches@atmel.com * 717447dc0d2Sludovic.desroches@atmel.com * This can be done by finding most significant bit set. 718447dc0d2Sludovic.desroches@atmel.com */ 719447dc0d2Sludovic.desroches@atmel.com static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, 720447dc0d2Sludovic.desroches@atmel.com unsigned int maxburst) 721447dc0d2Sludovic.desroches@atmel.com { 722447dc0d2Sludovic.desroches@atmel.com unsigned int version = atmci_get_version(host); 723447dc0d2Sludovic.desroches@atmel.com unsigned int offset = 2; 724447dc0d2Sludovic.desroches@atmel.com 725447dc0d2Sludovic.desroches@atmel.com if (version >= 0x600) 726447dc0d2Sludovic.desroches@atmel.com offset = 1; 727447dc0d2Sludovic.desroches@atmel.com 728447dc0d2Sludovic.desroches@atmel.com if (maxburst > 1) 729447dc0d2Sludovic.desroches@atmel.com return fls(maxburst) - offset; 730447dc0d2Sludovic.desroches@atmel.com else 731447dc0d2Sludovic.desroches@atmel.com return 0; 732447dc0d2Sludovic.desroches@atmel.com } 733447dc0d2Sludovic.desroches@atmel.com 73424011f34SLudovic Desroches static void atmci_timeout_timer(unsigned long data) 73524011f34SLudovic Desroches { 73624011f34SLudovic Desroches struct atmel_mci *host; 73724011f34SLudovic Desroches 73824011f34SLudovic Desroches host = (struct atmel_mci *)data; 73924011f34SLudovic Desroches 74024011f34SLudovic Desroches dev_dbg(&host->pdev->dev, "software timeout\n"); 74124011f34SLudovic Desroches 74224011f34SLudovic Desroches if (host->mrq->cmd->data) { 74324011f34SLudovic Desroches host->mrq->cmd->data->error = -ETIMEDOUT; 74424011f34SLudovic Desroches host->data = NULL; 745c1fa3426SLudovic Desroches /* 746c1fa3426SLudovic Desroches * With some SDIO modules, sometimes DMA transfer hangs. If 747c1fa3426SLudovic Desroches * stop_transfer() is not called then the DMA request is not 748c1fa3426SLudovic Desroches * removed, following ones are queued and never computed. 749c1fa3426SLudovic Desroches */ 750c1fa3426SLudovic Desroches if (host->state == STATE_DATA_XFER) 751c1fa3426SLudovic Desroches host->stop_transfer(host); 75224011f34SLudovic Desroches } else { 75324011f34SLudovic Desroches host->mrq->cmd->error = -ETIMEDOUT; 75424011f34SLudovic Desroches host->cmd = NULL; 75524011f34SLudovic Desroches } 75624011f34SLudovic Desroches host->need_reset = 1; 75724011f34SLudovic Desroches host->state = STATE_END_REQUEST; 75824011f34SLudovic Desroches smp_wmb(); 75924011f34SLudovic Desroches tasklet_schedule(&host->tasklet); 76024011f34SLudovic Desroches } 76124011f34SLudovic Desroches 7622c96a293SLudovic Desroches static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, 7637d2be074SHaavard Skinnemoen unsigned int ns) 7647d2be074SHaavard Skinnemoen { 76566292ad9SLudovic Desroches /* 76666292ad9SLudovic Desroches * It is easier here to use us instead of ns for the timeout, 76766292ad9SLudovic Desroches * it prevents from overflows during calculation. 76866292ad9SLudovic Desroches */ 76966292ad9SLudovic Desroches unsigned int us = DIV_ROUND_UP(ns, 1000); 77066292ad9SLudovic Desroches 77166292ad9SLudovic Desroches /* Maximum clock frequency is host->bus_hz/2 */ 77266292ad9SLudovic Desroches return us * (DIV_ROUND_UP(host->bus_hz, 2000000)); 7737d2be074SHaavard Skinnemoen } 7747d2be074SHaavard Skinnemoen 7757d2be074SHaavard Skinnemoen static void atmci_set_timeout(struct atmel_mci *host, 776965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot, struct mmc_data *data) 7777d2be074SHaavard Skinnemoen { 7787d2be074SHaavard Skinnemoen static unsigned dtomul_to_shift[] = { 7797d2be074SHaavard Skinnemoen 0, 4, 7, 8, 10, 12, 16, 20 7807d2be074SHaavard Skinnemoen }; 7817d2be074SHaavard Skinnemoen unsigned timeout; 7827d2be074SHaavard Skinnemoen unsigned dtocyc; 7837d2be074SHaavard Skinnemoen unsigned dtomul; 7847d2be074SHaavard Skinnemoen 7852c96a293SLudovic Desroches timeout = atmci_ns_to_clocks(host, data->timeout_ns) 7862c96a293SLudovic Desroches + data->timeout_clks; 7877d2be074SHaavard Skinnemoen 7887d2be074SHaavard Skinnemoen for (dtomul = 0; dtomul < 8; dtomul++) { 7897d2be074SHaavard Skinnemoen unsigned shift = dtomul_to_shift[dtomul]; 7907d2be074SHaavard Skinnemoen dtocyc = (timeout + (1 << shift) - 1) >> shift; 7917d2be074SHaavard Skinnemoen if (dtocyc < 15) 7927d2be074SHaavard Skinnemoen break; 7937d2be074SHaavard Skinnemoen } 7947d2be074SHaavard Skinnemoen 7957d2be074SHaavard Skinnemoen if (dtomul >= 8) { 7967d2be074SHaavard Skinnemoen dtomul = 7; 7977d2be074SHaavard Skinnemoen dtocyc = 15; 7987d2be074SHaavard Skinnemoen } 7997d2be074SHaavard Skinnemoen 800965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n", 8017d2be074SHaavard Skinnemoen dtocyc << dtomul_to_shift[dtomul]); 80203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); 8037d2be074SHaavard Skinnemoen } 8047d2be074SHaavard Skinnemoen 8057d2be074SHaavard Skinnemoen /* 8067d2be074SHaavard Skinnemoen * Return mask with command flags to be enabled for this command. 8077d2be074SHaavard Skinnemoen */ 8087d2be074SHaavard Skinnemoen static u32 atmci_prepare_command(struct mmc_host *mmc, 8097d2be074SHaavard Skinnemoen struct mmc_command *cmd) 8107d2be074SHaavard Skinnemoen { 8117d2be074SHaavard Skinnemoen struct mmc_data *data; 8127d2be074SHaavard Skinnemoen u32 cmdr; 8137d2be074SHaavard Skinnemoen 8147d2be074SHaavard Skinnemoen cmd->error = -EINPROGRESS; 8157d2be074SHaavard Skinnemoen 8162c96a293SLudovic Desroches cmdr = ATMCI_CMDR_CMDNB(cmd->opcode); 8177d2be074SHaavard Skinnemoen 8187d2be074SHaavard Skinnemoen if (cmd->flags & MMC_RSP_PRESENT) { 8197d2be074SHaavard Skinnemoen if (cmd->flags & MMC_RSP_136) 8202c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_RSPTYP_136BIT; 8217d2be074SHaavard Skinnemoen else 8222c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_RSPTYP_48BIT; 8237d2be074SHaavard Skinnemoen } 8247d2be074SHaavard Skinnemoen 8257d2be074SHaavard Skinnemoen /* 8267d2be074SHaavard Skinnemoen * This should really be MAXLAT_5 for CMD2 and ACMD41, but 8277d2be074SHaavard Skinnemoen * it's too difficult to determine whether this is an ACMD or 8287d2be074SHaavard Skinnemoen * not. Better make it 64. 8297d2be074SHaavard Skinnemoen */ 8302c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_MAXLAT_64CYC; 8317d2be074SHaavard Skinnemoen 8327d2be074SHaavard Skinnemoen if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) 8332c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_OPDCMD; 8347d2be074SHaavard Skinnemoen 8357d2be074SHaavard Skinnemoen data = cmd->data; 8367d2be074SHaavard Skinnemoen if (data) { 8372c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_START_XFER; 8382f1d7918SNicolas Ferre 8392f1d7918SNicolas Ferre if (cmd->opcode == SD_IO_RW_EXTENDED) { 8402c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_SDIO_BLOCK; 8412f1d7918SNicolas Ferre } else { 842fd551d94SJaehoon Chung if (data->blocks > 1) 8432c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_MULTI_BLOCK; 8447d2be074SHaavard Skinnemoen else 8452c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_BLOCK; 8462f1d7918SNicolas Ferre } 8477d2be074SHaavard Skinnemoen 8487d2be074SHaavard Skinnemoen if (data->flags & MMC_DATA_READ) 8492c96a293SLudovic Desroches cmdr |= ATMCI_CMDR_TRDIR_READ; 8507d2be074SHaavard Skinnemoen } 8517d2be074SHaavard Skinnemoen 8527d2be074SHaavard Skinnemoen return cmdr; 8537d2be074SHaavard Skinnemoen } 8547d2be074SHaavard Skinnemoen 85511d1488bSLudovic Desroches static void atmci_send_command(struct atmel_mci *host, 856965ebf33SHaavard Skinnemoen struct mmc_command *cmd, u32 cmd_flags) 8577d2be074SHaavard Skinnemoen { 8587d2be074SHaavard Skinnemoen WARN_ON(host->cmd); 8597d2be074SHaavard Skinnemoen host->cmd = cmd; 8607d2be074SHaavard Skinnemoen 861965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, 8627d2be074SHaavard Skinnemoen "start command: ARGR=0x%08x CMDR=0x%08x\n", 8637d2be074SHaavard Skinnemoen cmd->arg, cmd_flags); 8647d2be074SHaavard Skinnemoen 86503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_ARGR, cmd->arg); 86603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CMDR, cmd_flags); 8677d2be074SHaavard Skinnemoen } 8687d2be074SHaavard Skinnemoen 8692c96a293SLudovic Desroches static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) 8707d2be074SHaavard Skinnemoen { 8716801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "send stop command\n"); 87211d1488bSLudovic Desroches atmci_send_command(host, data->stop, host->stop_cmdr); 87303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); 8747d2be074SHaavard Skinnemoen } 8757d2be074SHaavard Skinnemoen 876796211b7SLudovic Desroches /* 877796211b7SLudovic Desroches * Configure given PDC buffer taking care of alignement issues. 878796211b7SLudovic Desroches * Update host->data_size and host->sg. 879796211b7SLudovic Desroches */ 880796211b7SLudovic Desroches static void atmci_pdc_set_single_buf(struct atmel_mci *host, 881796211b7SLudovic Desroches enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) 882796211b7SLudovic Desroches { 883796211b7SLudovic Desroches u32 pointer_reg, counter_reg; 8847a90dcc2SLudovic Desroches unsigned int buf_size; 885796211b7SLudovic Desroches 886796211b7SLudovic Desroches if (dir == XFER_RECEIVE) { 887796211b7SLudovic Desroches pointer_reg = ATMEL_PDC_RPR; 888796211b7SLudovic Desroches counter_reg = ATMEL_PDC_RCR; 889796211b7SLudovic Desroches } else { 890796211b7SLudovic Desroches pointer_reg = ATMEL_PDC_TPR; 891796211b7SLudovic Desroches counter_reg = ATMEL_PDC_TCR; 892796211b7SLudovic Desroches } 893796211b7SLudovic Desroches 894796211b7SLudovic Desroches if (buf_nb == PDC_SECOND_BUF) { 8951ebbe3d3SLudovic Desroches pointer_reg += ATMEL_PDC_SCND_BUF_OFF; 8961ebbe3d3SLudovic Desroches counter_reg += ATMEL_PDC_SCND_BUF_OFF; 897796211b7SLudovic Desroches } 898796211b7SLudovic Desroches 8997a90dcc2SLudovic Desroches if (!host->caps.has_rwproof) { 9007a90dcc2SLudovic Desroches buf_size = host->buf_size; 9017a90dcc2SLudovic Desroches atmci_writel(host, pointer_reg, host->buf_phys_addr); 9027a90dcc2SLudovic Desroches } else { 9037a90dcc2SLudovic Desroches buf_size = sg_dma_len(host->sg); 904796211b7SLudovic Desroches atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); 9057a90dcc2SLudovic Desroches } 9067a90dcc2SLudovic Desroches 9077a90dcc2SLudovic Desroches if (host->data_size <= buf_size) { 908796211b7SLudovic Desroches if (host->data_size & 0x3) { 909796211b7SLudovic Desroches /* If size is different from modulo 4, transfer bytes */ 910796211b7SLudovic Desroches atmci_writel(host, counter_reg, host->data_size); 911796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE); 912796211b7SLudovic Desroches } else { 913796211b7SLudovic Desroches /* Else transfer 32-bits words */ 914796211b7SLudovic Desroches atmci_writel(host, counter_reg, host->data_size / 4); 915796211b7SLudovic Desroches } 916796211b7SLudovic Desroches host->data_size = 0; 917796211b7SLudovic Desroches } else { 918796211b7SLudovic Desroches /* We assume the size of a page is 32-bits aligned */ 919341fa4c3SLudovic Desroches atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4); 920341fa4c3SLudovic Desroches host->data_size -= sg_dma_len(host->sg); 921796211b7SLudovic Desroches if (host->data_size) 922796211b7SLudovic Desroches host->sg = sg_next(host->sg); 923796211b7SLudovic Desroches } 924796211b7SLudovic Desroches } 925796211b7SLudovic Desroches 926796211b7SLudovic Desroches /* 927796211b7SLudovic Desroches * Configure PDC buffer according to the data size ie configuring one or two 928796211b7SLudovic Desroches * buffers. Don't use this function if you want to configure only the second 929796211b7SLudovic Desroches * buffer. In this case, use atmci_pdc_set_single_buf. 930796211b7SLudovic Desroches */ 931796211b7SLudovic Desroches static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir) 932796211b7SLudovic Desroches { 933796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF); 934796211b7SLudovic Desroches if (host->data_size) 935796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF); 936796211b7SLudovic Desroches } 937796211b7SLudovic Desroches 938796211b7SLudovic Desroches /* 939796211b7SLudovic Desroches * Unmap sg lists, called when transfer is finished. 940796211b7SLudovic Desroches */ 941796211b7SLudovic Desroches static void atmci_pdc_cleanup(struct atmel_mci *host) 942796211b7SLudovic Desroches { 943796211b7SLudovic Desroches struct mmc_data *data = host->data; 944796211b7SLudovic Desroches 945796211b7SLudovic Desroches if (data) 946796211b7SLudovic Desroches dma_unmap_sg(&host->pdev->dev, 947796211b7SLudovic Desroches data->sg, data->sg_len, 948feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 949796211b7SLudovic Desroches } 950796211b7SLudovic Desroches 951796211b7SLudovic Desroches /* 952796211b7SLudovic Desroches * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after 953796211b7SLudovic Desroches * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY 954796211b7SLudovic Desroches * interrupt needed for both transfer directions. 955796211b7SLudovic Desroches */ 956796211b7SLudovic Desroches static void atmci_pdc_complete(struct atmel_mci *host) 957796211b7SLudovic Desroches { 9587a90dcc2SLudovic Desroches int transfer_size = host->data->blocks * host->data->blksz; 95924011f34SLudovic Desroches int i; 9607a90dcc2SLudovic Desroches 961796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); 9627a90dcc2SLudovic Desroches 9637a90dcc2SLudovic Desroches if ((!host->caps.has_rwproof) 96424011f34SLudovic Desroches && (host->data->flags & MMC_DATA_READ)) { 96524011f34SLudovic Desroches if (host->caps.has_bad_data_ordering) 96624011f34SLudovic Desroches for (i = 0; i < transfer_size; i++) 96724011f34SLudovic Desroches host->buffer[i] = swab32(host->buffer[i]); 9687a90dcc2SLudovic Desroches sg_copy_from_buffer(host->data->sg, host->data->sg_len, 9697a90dcc2SLudovic Desroches host->buffer, transfer_size); 97024011f34SLudovic Desroches } 9717a90dcc2SLudovic Desroches 972796211b7SLudovic Desroches atmci_pdc_cleanup(host); 973796211b7SLudovic Desroches 9746e9e4062SAlexandre Belloni dev_dbg(&host->pdev->dev, "(%s) set pending xfer complete\n", __func__); 975796211b7SLudovic Desroches atmci_set_pending(host, EVENT_XFER_COMPLETE); 976796211b7SLudovic Desroches tasklet_schedule(&host->tasklet); 977796211b7SLudovic Desroches } 978796211b7SLudovic Desroches 97965e8b083SHaavard Skinnemoen static void atmci_dma_cleanup(struct atmel_mci *host) 98065e8b083SHaavard Skinnemoen { 98165e8b083SHaavard Skinnemoen struct mmc_data *data = host->data; 98265e8b083SHaavard Skinnemoen 983009a891bSNicolas Ferre if (data) 984266ac3f2SLinus Walleij dma_unmap_sg(host->dma.chan->device->dev, 985266ac3f2SLinus Walleij data->sg, data->sg_len, 986feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 98765e8b083SHaavard Skinnemoen } 98865e8b083SHaavard Skinnemoen 989796211b7SLudovic Desroches /* 990796211b7SLudovic Desroches * This function is called by the DMA driver from tasklet context. 991796211b7SLudovic Desroches */ 99265e8b083SHaavard Skinnemoen static void atmci_dma_complete(void *arg) 99365e8b083SHaavard Skinnemoen { 99465e8b083SHaavard Skinnemoen struct atmel_mci *host = arg; 99565e8b083SHaavard Skinnemoen struct mmc_data *data = host->data; 99665e8b083SHaavard Skinnemoen 99765e8b083SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "DMA complete\n"); 99865e8b083SHaavard Skinnemoen 999ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) 100074791a2dSNicolas Ferre /* Disable DMA hardware handshaking on MCI */ 100103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); 100274791a2dSNicolas Ferre 100365e8b083SHaavard Skinnemoen atmci_dma_cleanup(host); 100465e8b083SHaavard Skinnemoen 100565e8b083SHaavard Skinnemoen /* 100665e8b083SHaavard Skinnemoen * If the card was removed, data will be NULL. No point trying 100765e8b083SHaavard Skinnemoen * to send the stop command or waiting for NBUSY in this case. 100865e8b083SHaavard Skinnemoen */ 100965e8b083SHaavard Skinnemoen if (data) { 10106801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 10116801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 101265e8b083SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 101365e8b083SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 101465e8b083SHaavard Skinnemoen 101565e8b083SHaavard Skinnemoen /* 101665e8b083SHaavard Skinnemoen * Regardless of what the documentation says, we have 101765e8b083SHaavard Skinnemoen * to wait for NOTBUSY even after block read 101865e8b083SHaavard Skinnemoen * operations. 101965e8b083SHaavard Skinnemoen * 102065e8b083SHaavard Skinnemoen * When the DMA transfer is complete, the controller 102165e8b083SHaavard Skinnemoen * may still be reading the CRC from the card, i.e. 102265e8b083SHaavard Skinnemoen * the data transfer is still in progress and we 102365e8b083SHaavard Skinnemoen * haven't seen all the potential error bits yet. 102465e8b083SHaavard Skinnemoen * 102565e8b083SHaavard Skinnemoen * The interrupt handler will schedule a different 102665e8b083SHaavard Skinnemoen * tasklet to finish things up when the data transfer 102765e8b083SHaavard Skinnemoen * is completely done. 102865e8b083SHaavard Skinnemoen * 102965e8b083SHaavard Skinnemoen * We may not complete the mmc request here anyway 103065e8b083SHaavard Skinnemoen * because the mmc layer may call back and cause us to 103165e8b083SHaavard Skinnemoen * violate the "don't submit new operations from the 103265e8b083SHaavard Skinnemoen * completion callback" rule of the dma engine 103365e8b083SHaavard Skinnemoen * framework. 103465e8b083SHaavard Skinnemoen */ 103503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 103665e8b083SHaavard Skinnemoen } 103765e8b083SHaavard Skinnemoen } 103865e8b083SHaavard Skinnemoen 1039796211b7SLudovic Desroches /* 1040796211b7SLudovic Desroches * Returns a mask of interrupt flags to be enabled after the whole 1041796211b7SLudovic Desroches * request has been prepared. 1042796211b7SLudovic Desroches */ 1043796211b7SLudovic Desroches static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) 1044796211b7SLudovic Desroches { 1045796211b7SLudovic Desroches u32 iflags; 1046796211b7SLudovic Desroches 1047796211b7SLudovic Desroches data->error = -EINPROGRESS; 1048796211b7SLudovic Desroches 1049796211b7SLudovic Desroches host->sg = data->sg; 1050bdbc5d0cSTerry Barnaby host->sg_len = data->sg_len; 1051796211b7SLudovic Desroches host->data = data; 1052796211b7SLudovic Desroches host->data_chan = NULL; 1053796211b7SLudovic Desroches 1054796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 1055796211b7SLudovic Desroches 1056796211b7SLudovic Desroches /* 1057796211b7SLudovic Desroches * Errata: MMC data write operation with less than 12 1058796211b7SLudovic Desroches * bytes is impossible. 1059796211b7SLudovic Desroches * 1060796211b7SLudovic Desroches * Errata: MCI Transmit Data Register (TDR) FIFO 1061796211b7SLudovic Desroches * corruption when length is not multiple of 4. 1062796211b7SLudovic Desroches */ 1063796211b7SLudovic Desroches if (data->blocks * data->blksz < 12 1064796211b7SLudovic Desroches || (data->blocks * data->blksz) & 3) 1065796211b7SLudovic Desroches host->need_reset = true; 1066796211b7SLudovic Desroches 1067796211b7SLudovic Desroches host->pio_offset = 0; 1068796211b7SLudovic Desroches if (data->flags & MMC_DATA_READ) 1069796211b7SLudovic Desroches iflags |= ATMCI_RXRDY; 1070796211b7SLudovic Desroches else 1071796211b7SLudovic Desroches iflags |= ATMCI_TXRDY; 1072796211b7SLudovic Desroches 1073796211b7SLudovic Desroches return iflags; 1074796211b7SLudovic Desroches } 1075796211b7SLudovic Desroches 1076796211b7SLudovic Desroches /* 1077796211b7SLudovic Desroches * Set interrupt flags and set block length into the MCI mode register even 1078796211b7SLudovic Desroches * if this value is also accessible in the MCI block register. It seems to be 1079796211b7SLudovic Desroches * necessary before the High Speed MCI version. It also map sg and configure 1080796211b7SLudovic Desroches * PDC registers. 1081796211b7SLudovic Desroches */ 1082796211b7SLudovic Desroches static u32 1083796211b7SLudovic Desroches atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) 1084796211b7SLudovic Desroches { 1085796211b7SLudovic Desroches u32 iflags, tmp; 108624011f34SLudovic Desroches int i; 1087796211b7SLudovic Desroches 1088796211b7SLudovic Desroches data->error = -EINPROGRESS; 1089796211b7SLudovic Desroches 1090796211b7SLudovic Desroches host->data = data; 1091796211b7SLudovic Desroches host->sg = data->sg; 1092796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 1093796211b7SLudovic Desroches 1094796211b7SLudovic Desroches /* Enable pdc mode */ 1095796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE); 1096796211b7SLudovic Desroches 1097feeef096SHeiner Kallweit if (data->flags & MMC_DATA_READ) 1098796211b7SLudovic Desroches iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; 1099feeef096SHeiner Kallweit else 1100f5177547SLudovic Desroches iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; 1101796211b7SLudovic Desroches 1102796211b7SLudovic Desroches /* Set BLKLEN */ 1103796211b7SLudovic Desroches tmp = atmci_readl(host, ATMCI_MR); 1104796211b7SLudovic Desroches tmp &= 0x0000ffff; 1105796211b7SLudovic Desroches tmp |= ATMCI_BLKLEN(data->blksz); 1106796211b7SLudovic Desroches atmci_writel(host, ATMCI_MR, tmp); 1107796211b7SLudovic Desroches 1108796211b7SLudovic Desroches /* Configure PDC */ 1109796211b7SLudovic Desroches host->data_size = data->blocks * data->blksz; 1110f98e0d5aSShawn Lin dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, 1111feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 11127a90dcc2SLudovic Desroches 11137a90dcc2SLudovic Desroches if ((!host->caps.has_rwproof) 111424011f34SLudovic Desroches && (host->data->flags & MMC_DATA_WRITE)) { 11157a90dcc2SLudovic Desroches sg_copy_to_buffer(host->data->sg, host->data->sg_len, 11167a90dcc2SLudovic Desroches host->buffer, host->data_size); 111724011f34SLudovic Desroches if (host->caps.has_bad_data_ordering) 111824011f34SLudovic Desroches for (i = 0; i < host->data_size; i++) 111924011f34SLudovic Desroches host->buffer[i] = swab32(host->buffer[i]); 112024011f34SLudovic Desroches } 11217a90dcc2SLudovic Desroches 1122796211b7SLudovic Desroches if (host->data_size) 1123feeef096SHeiner Kallweit atmci_pdc_set_both_buf(host, data->flags & MMC_DATA_READ ? 1124feeef096SHeiner Kallweit XFER_RECEIVE : XFER_TRANSMIT); 1125796211b7SLudovic Desroches return iflags; 1126796211b7SLudovic Desroches } 1127796211b7SLudovic Desroches 1128796211b7SLudovic Desroches static u32 112974791a2dSNicolas Ferre atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) 113065e8b083SHaavard Skinnemoen { 113165e8b083SHaavard Skinnemoen struct dma_chan *chan; 113265e8b083SHaavard Skinnemoen struct dma_async_tx_descriptor *desc; 113365e8b083SHaavard Skinnemoen struct scatterlist *sg; 113465e8b083SHaavard Skinnemoen unsigned int i; 113505f5799cSVinod Koul enum dma_transfer_direction slave_dirn; 1136657a77faSAtsushi Nemoto unsigned int sglen; 1137693e5e20SNicolas Ferre u32 maxburst; 1138796211b7SLudovic Desroches u32 iflags; 1139796211b7SLudovic Desroches 1140796211b7SLudovic Desroches data->error = -EINPROGRESS; 1141796211b7SLudovic Desroches 1142796211b7SLudovic Desroches WARN_ON(host->data); 1143796211b7SLudovic Desroches host->sg = NULL; 1144796211b7SLudovic Desroches host->data = data; 1145796211b7SLudovic Desroches 1146796211b7SLudovic Desroches iflags = ATMCI_DATA_ERROR_FLAGS; 114765e8b083SHaavard Skinnemoen 114865e8b083SHaavard Skinnemoen /* 114965e8b083SHaavard Skinnemoen * We don't do DMA on "complex" transfers, i.e. with 115065e8b083SHaavard Skinnemoen * non-word-aligned buffers or lengths. Also, we don't bother 115165e8b083SHaavard Skinnemoen * with all the DMA setup overhead for short transfers. 115265e8b083SHaavard Skinnemoen */ 1153796211b7SLudovic Desroches if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) 1154796211b7SLudovic Desroches return atmci_prepare_data(host, data); 115565e8b083SHaavard Skinnemoen if (data->blksz & 3) 1156796211b7SLudovic Desroches return atmci_prepare_data(host, data); 115765e8b083SHaavard Skinnemoen 115865e8b083SHaavard Skinnemoen for_each_sg(data->sg, sg, data->sg_len, i) { 115965e8b083SHaavard Skinnemoen if (sg->offset & 3 || sg->length & 3) 1160796211b7SLudovic Desroches return atmci_prepare_data(host, data); 116165e8b083SHaavard Skinnemoen } 116265e8b083SHaavard Skinnemoen 116365e8b083SHaavard Skinnemoen /* If we don't have a channel, we can't do DMA */ 116465e8b083SHaavard Skinnemoen chan = host->dma.chan; 11656f49a57aSDan Williams if (chan) 116665e8b083SHaavard Skinnemoen host->data_chan = chan; 116765e8b083SHaavard Skinnemoen 116865e8b083SHaavard Skinnemoen if (!chan) 116965e8b083SHaavard Skinnemoen return -ENODEV; 117065e8b083SHaavard Skinnemoen 117105f5799cSVinod Koul if (data->flags & MMC_DATA_READ) { 1172e2b35f3dSViresh Kumar host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; 1173447dc0d2Sludovic.desroches@atmel.com maxburst = atmci_convert_chksize(host, 1174447dc0d2Sludovic.desroches@atmel.com host->dma_conf.src_maxburst); 117505f5799cSVinod Koul } else { 1176e2b35f3dSViresh Kumar host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; 1177447dc0d2Sludovic.desroches@atmel.com maxburst = atmci_convert_chksize(host, 1178447dc0d2Sludovic.desroches@atmel.com host->dma_conf.dst_maxburst); 117905f5799cSVinod Koul } 118065e8b083SHaavard Skinnemoen 1181ccdfe612SHein_Tibosch if (host->caps.has_dma_conf_reg) 1182ccdfe612SHein_Tibosch atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | 1183ccdfe612SHein_Tibosch ATMCI_DMAEN); 1184693e5e20SNicolas Ferre 1185266ac3f2SLinus Walleij sglen = dma_map_sg(chan->device->dev, data->sg, 1186feeef096SHeiner Kallweit data->sg_len, mmc_get_dma_dir(data)); 118788ce4db3SLinus Walleij 1188e2b35f3dSViresh Kumar dmaengine_slave_config(chan, &host->dma_conf); 118916052827SAlexandre Bounine desc = dmaengine_prep_slave_sg(chan, 119005f5799cSVinod Koul data->sg, sglen, slave_dirn, 119165e8b083SHaavard Skinnemoen DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 119265e8b083SHaavard Skinnemoen if (!desc) 1193657a77faSAtsushi Nemoto goto unmap_exit; 119465e8b083SHaavard Skinnemoen 119565e8b083SHaavard Skinnemoen host->dma.data_desc = desc; 119665e8b083SHaavard Skinnemoen desc->callback = atmci_dma_complete; 119765e8b083SHaavard Skinnemoen desc->callback_param = host; 119865e8b083SHaavard Skinnemoen 1199796211b7SLudovic Desroches return iflags; 1200657a77faSAtsushi Nemoto unmap_exit: 1201feeef096SHeiner Kallweit dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, 1202feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 1203657a77faSAtsushi Nemoto return -ENOMEM; 120465e8b083SHaavard Skinnemoen } 120565e8b083SHaavard Skinnemoen 1206796211b7SLudovic Desroches static void 1207796211b7SLudovic Desroches atmci_submit_data(struct atmel_mci *host, struct mmc_data *data) 1208796211b7SLudovic Desroches { 1209796211b7SLudovic Desroches return; 1210796211b7SLudovic Desroches } 1211796211b7SLudovic Desroches 1212796211b7SLudovic Desroches /* 1213796211b7SLudovic Desroches * Start PDC according to transfer direction. 1214796211b7SLudovic Desroches */ 1215796211b7SLudovic Desroches static void 1216796211b7SLudovic Desroches atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data) 1217796211b7SLudovic Desroches { 1218796211b7SLudovic Desroches if (data->flags & MMC_DATA_READ) 1219796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); 1220796211b7SLudovic Desroches else 1221796211b7SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); 1222796211b7SLudovic Desroches } 1223796211b7SLudovic Desroches 1224796211b7SLudovic Desroches static void 1225796211b7SLudovic Desroches atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) 122674791a2dSNicolas Ferre { 122774791a2dSNicolas Ferre struct dma_chan *chan = host->data_chan; 122874791a2dSNicolas Ferre struct dma_async_tx_descriptor *desc = host->dma.data_desc; 122974791a2dSNicolas Ferre 123074791a2dSNicolas Ferre if (chan) { 12315328906aSLinus Walleij dmaengine_submit(desc); 12325328906aSLinus Walleij dma_async_issue_pending(chan); 123374791a2dSNicolas Ferre } 123474791a2dSNicolas Ferre } 123574791a2dSNicolas Ferre 1236796211b7SLudovic Desroches static void atmci_stop_transfer(struct atmel_mci *host) 123765e8b083SHaavard Skinnemoen { 12386801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 12396801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 124065e8b083SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 124103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 124265e8b083SHaavard Skinnemoen } 124365e8b083SHaavard Skinnemoen 12447d2be074SHaavard Skinnemoen /* 12457122bbb0SMasanari Iida * Stop data transfer because error(s) occurred. 12467d2be074SHaavard Skinnemoen */ 1247796211b7SLudovic Desroches static void atmci_stop_transfer_pdc(struct atmel_mci *host) 12487d2be074SHaavard Skinnemoen { 1249f5177547SLudovic Desroches atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); 1250796211b7SLudovic Desroches } 12517d2be074SHaavard Skinnemoen 1252796211b7SLudovic Desroches static void atmci_stop_transfer_dma(struct atmel_mci *host) 1253796211b7SLudovic Desroches { 1254796211b7SLudovic Desroches struct dma_chan *chan = host->data_chan; 12557d2be074SHaavard Skinnemoen 1256796211b7SLudovic Desroches if (chan) { 1257796211b7SLudovic Desroches dmaengine_terminate_all(chan); 1258796211b7SLudovic Desroches atmci_dma_cleanup(host); 1259796211b7SLudovic Desroches } else { 1260796211b7SLudovic Desroches /* Data transfer was stopped by the interrupt handler */ 12616801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 12626801c41aSLudovic Desroches "(%s) set pending xfer complete\n", __func__); 1263796211b7SLudovic Desroches atmci_set_pending(host, EVENT_XFER_COMPLETE); 1264796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1265796211b7SLudovic Desroches } 1266796211b7SLudovic Desroches } 1267965ebf33SHaavard Skinnemoen 1268965ebf33SHaavard Skinnemoen /* 1269796211b7SLudovic Desroches * Start a request: prepare data if needed, prepare the command and activate 1270796211b7SLudovic Desroches * interrupts. 1271965ebf33SHaavard Skinnemoen */ 1272965ebf33SHaavard Skinnemoen static void atmci_start_request(struct atmel_mci *host, 1273965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot) 12747d2be074SHaavard Skinnemoen { 1275965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 12767d2be074SHaavard Skinnemoen struct mmc_command *cmd; 1277965ebf33SHaavard Skinnemoen struct mmc_data *data; 12787d2be074SHaavard Skinnemoen u32 iflags; 1279965ebf33SHaavard Skinnemoen u32 cmdflags; 1280965ebf33SHaavard Skinnemoen 1281965ebf33SHaavard Skinnemoen mrq = slot->mrq; 1282965ebf33SHaavard Skinnemoen host->cur_slot = slot; 1283965ebf33SHaavard Skinnemoen host->mrq = mrq; 1284965ebf33SHaavard Skinnemoen 1285965ebf33SHaavard Skinnemoen host->pending_events = 0; 1286965ebf33SHaavard Skinnemoen host->completed_events = 0; 1287f5177547SLudovic Desroches host->cmd_status = 0; 1288ca55f46eSHaavard Skinnemoen host->data_status = 0; 1289965ebf33SHaavard Skinnemoen 12906801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode); 12916801c41aSLudovic Desroches 129224011f34SLudovic Desroches if (host->need_reset || host->caps.need_reset_after_xfer) { 129318ee684bSLudovic Desroches iflags = atmci_readl(host, ATMCI_IMR); 129418ee684bSLudovic Desroches iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); 129503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 129603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 129703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1298796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 129903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 130018ee684bSLudovic Desroches atmci_writel(host, ATMCI_IER, iflags); 1301965ebf33SHaavard Skinnemoen host->need_reset = false; 1302965ebf33SHaavard Skinnemoen } 130303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); 13047d2be074SHaavard Skinnemoen 130503fc9a7fSLudovic Desroches iflags = atmci_readl(host, ATMCI_IMR); 13062c96a293SLudovic Desroches if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) 1307f5177547SLudovic Desroches dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", 1308965ebf33SHaavard Skinnemoen iflags); 13097d2be074SHaavard Skinnemoen 1310965ebf33SHaavard Skinnemoen if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { 1311965ebf33SHaavard Skinnemoen /* Send init sequence (74 clock cycles) */ 131203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); 131303fc9a7fSLudovic Desroches while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY)) 1314965ebf33SHaavard Skinnemoen cpu_relax(); 13157d2be074SHaavard Skinnemoen } 131674791a2dSNicolas Ferre iflags = 0; 13177d2be074SHaavard Skinnemoen data = mrq->data; 13187d2be074SHaavard Skinnemoen if (data) { 1319965ebf33SHaavard Skinnemoen atmci_set_timeout(host, slot, data); 1320a252e3e3SHaavard Skinnemoen 1321a252e3e3SHaavard Skinnemoen /* Must set block count/size before sending command */ 132203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) 13232c96a293SLudovic Desroches | ATMCI_BLKLEN(data->blksz)); 1324965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", 13252c96a293SLudovic Desroches ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); 132674791a2dSNicolas Ferre 1327796211b7SLudovic Desroches iflags |= host->prepare_data(host, data); 13287d2be074SHaavard Skinnemoen } 13297d2be074SHaavard Skinnemoen 13302c96a293SLudovic Desroches iflags |= ATMCI_CMDRDY; 13317d2be074SHaavard Skinnemoen cmd = mrq->cmd; 1332965ebf33SHaavard Skinnemoen cmdflags = atmci_prepare_command(slot->mmc, cmd); 133366b512edSLudovic Desroches 133466b512edSLudovic Desroches /* 133566b512edSLudovic Desroches * DMA transfer should be started before sending the command to avoid 133666b512edSLudovic Desroches * unexpected errors especially for read operations in SDIO mode. 133766b512edSLudovic Desroches * Unfortunately, in PDC mode, command has to be sent before starting 133866b512edSLudovic Desroches * the transfer. 133966b512edSLudovic Desroches */ 134066b512edSLudovic Desroches if (host->submit_data != &atmci_submit_data_dma) 134111d1488bSLudovic Desroches atmci_send_command(host, cmd, cmdflags); 13427d2be074SHaavard Skinnemoen 13437d2be074SHaavard Skinnemoen if (data) 1344796211b7SLudovic Desroches host->submit_data(host, data); 13457d2be074SHaavard Skinnemoen 134666b512edSLudovic Desroches if (host->submit_data == &atmci_submit_data_dma) 134766b512edSLudovic Desroches atmci_send_command(host, cmd, cmdflags); 134866b512edSLudovic Desroches 13497d2be074SHaavard Skinnemoen if (mrq->stop) { 1350965ebf33SHaavard Skinnemoen host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); 13512c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; 13527d2be074SHaavard Skinnemoen if (!(data->flags & MMC_DATA_WRITE)) 13532c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; 13542c96a293SLudovic Desroches host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; 13557d2be074SHaavard Skinnemoen } 13567d2be074SHaavard Skinnemoen 13577d2be074SHaavard Skinnemoen /* 13587d2be074SHaavard Skinnemoen * We could have enabled interrupts earlier, but I suspect 13597d2be074SHaavard Skinnemoen * that would open up a nice can of interesting race 13607d2be074SHaavard Skinnemoen * conditions (e.g. command and data complete, but stop not 13617d2be074SHaavard Skinnemoen * prepared yet.) 13627d2be074SHaavard Skinnemoen */ 136303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, iflags); 136424011f34SLudovic Desroches 136524011f34SLudovic Desroches mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); 1366965ebf33SHaavard Skinnemoen } 13677d2be074SHaavard Skinnemoen 1368965ebf33SHaavard Skinnemoen static void atmci_queue_request(struct atmel_mci *host, 1369965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot, struct mmc_request *mrq) 1370965ebf33SHaavard Skinnemoen { 1371965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 1372965ebf33SHaavard Skinnemoen host->state); 1373965ebf33SHaavard Skinnemoen 1374965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1375965ebf33SHaavard Skinnemoen slot->mrq = mrq; 1376965ebf33SHaavard Skinnemoen if (host->state == STATE_IDLE) { 1377965ebf33SHaavard Skinnemoen host->state = STATE_SENDING_CMD; 1378965ebf33SHaavard Skinnemoen atmci_start_request(host, slot); 1379965ebf33SHaavard Skinnemoen } else { 13806801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "queue request\n"); 1381965ebf33SHaavard Skinnemoen list_add_tail(&slot->queue_node, &host->queue); 1382965ebf33SHaavard Skinnemoen } 1383965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1384965ebf33SHaavard Skinnemoen } 1385965ebf33SHaavard Skinnemoen 1386965ebf33SHaavard Skinnemoen static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1387965ebf33SHaavard Skinnemoen { 1388965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1389965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1390965ebf33SHaavard Skinnemoen struct mmc_data *data; 1391965ebf33SHaavard Skinnemoen 1392965ebf33SHaavard Skinnemoen WARN_ON(slot->mrq); 13936801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); 1394965ebf33SHaavard Skinnemoen 1395965ebf33SHaavard Skinnemoen /* 1396965ebf33SHaavard Skinnemoen * We may "know" the card is gone even though there's still an 1397965ebf33SHaavard Skinnemoen * electrical connection. If so, we really need to communicate 1398965ebf33SHaavard Skinnemoen * this to the MMC core since there won't be any more 1399965ebf33SHaavard Skinnemoen * interrupts as the card is completely removed. Otherwise, 1400965ebf33SHaavard Skinnemoen * the MMC core might believe the card is still there even 1401965ebf33SHaavard Skinnemoen * though the card was just removed very slowly. 1402965ebf33SHaavard Skinnemoen */ 1403965ebf33SHaavard Skinnemoen if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) { 1404965ebf33SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1405965ebf33SHaavard Skinnemoen mmc_request_done(mmc, mrq); 14067d2be074SHaavard Skinnemoen return; 1407965ebf33SHaavard Skinnemoen } 14087d2be074SHaavard Skinnemoen 1409965ebf33SHaavard Skinnemoen /* We don't support multiple blocks of weird lengths. */ 1410965ebf33SHaavard Skinnemoen data = mrq->data; 1411965ebf33SHaavard Skinnemoen if (data && data->blocks > 1 && data->blksz & 3) { 14127d2be074SHaavard Skinnemoen mrq->cmd->error = -EINVAL; 14137d2be074SHaavard Skinnemoen mmc_request_done(mmc, mrq); 14147d2be074SHaavard Skinnemoen } 14157d2be074SHaavard Skinnemoen 1416965ebf33SHaavard Skinnemoen atmci_queue_request(host, slot, mrq); 1417965ebf33SHaavard Skinnemoen } 1418965ebf33SHaavard Skinnemoen 14197d2be074SHaavard Skinnemoen static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 14207d2be074SHaavard Skinnemoen { 1421965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1422965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1423965ebf33SHaavard Skinnemoen unsigned int i; 1424ae552ab0SWenyou Yang 14252c96a293SLudovic Desroches slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; 1426945533b5SHaavard Skinnemoen switch (ios->bus_width) { 1427945533b5SHaavard Skinnemoen case MMC_BUS_WIDTH_1: 14282c96a293SLudovic Desroches slot->sdc_reg |= ATMCI_SDCBUS_1BIT; 1429945533b5SHaavard Skinnemoen break; 1430945533b5SHaavard Skinnemoen case MMC_BUS_WIDTH_4: 14312c96a293SLudovic Desroches slot->sdc_reg |= ATMCI_SDCBUS_4BIT; 1432945533b5SHaavard Skinnemoen break; 1433945533b5SHaavard Skinnemoen } 1434945533b5SHaavard Skinnemoen 14357d2be074SHaavard Skinnemoen if (ios->clock) { 1436965ebf33SHaavard Skinnemoen unsigned int clock_min = ~0U; 143760c8f783SLudovic Desroches int clkdiv; 14387d2be074SHaavard Skinnemoen 1439965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1440965ebf33SHaavard Skinnemoen if (!host->mode_reg) { 144103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 144203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 1443796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 144403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 1445965ebf33SHaavard Skinnemoen } 1446945533b5SHaavard Skinnemoen 1447965ebf33SHaavard Skinnemoen /* 1448965ebf33SHaavard Skinnemoen * Use mirror of ios->clock to prevent race with mmc 1449965ebf33SHaavard Skinnemoen * core ios update when finding the minimum. 1450965ebf33SHaavard Skinnemoen */ 1451965ebf33SHaavard Skinnemoen slot->clock = ios->clock; 14522c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 1453965ebf33SHaavard Skinnemoen if (host->slot[i] && host->slot[i]->clock 1454965ebf33SHaavard Skinnemoen && host->slot[i]->clock < clock_min) 1455965ebf33SHaavard Skinnemoen clock_min = host->slot[i]->clock; 1456965ebf33SHaavard Skinnemoen } 1457965ebf33SHaavard Skinnemoen 1458965ebf33SHaavard Skinnemoen /* Calculate clock divider */ 1459faf8180bSLudovic Desroches if (host->caps.has_odd_clk_div) { 1460faf8180bSLudovic Desroches clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; 146160c8f783SLudovic Desroches if (clkdiv < 0) { 146260c8f783SLudovic Desroches dev_warn(&mmc->class_dev, 146360c8f783SLudovic Desroches "clock %u too fast; using %lu\n", 146460c8f783SLudovic Desroches clock_min, host->bus_hz / 2); 146560c8f783SLudovic Desroches clkdiv = 0; 146660c8f783SLudovic Desroches } else if (clkdiv > 511) { 1467faf8180bSLudovic Desroches dev_warn(&mmc->class_dev, 1468faf8180bSLudovic Desroches "clock %u too slow; using %lu\n", 1469faf8180bSLudovic Desroches clock_min, host->bus_hz / (511 + 2)); 1470faf8180bSLudovic Desroches clkdiv = 511; 1471faf8180bSLudovic Desroches } 1472faf8180bSLudovic Desroches host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) 1473faf8180bSLudovic Desroches | ATMCI_MR_CLKODD(clkdiv & 1); 1474faf8180bSLudovic Desroches } else { 1475965ebf33SHaavard Skinnemoen clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; 14767d2be074SHaavard Skinnemoen if (clkdiv > 255) { 14777d2be074SHaavard Skinnemoen dev_warn(&mmc->class_dev, 14787d2be074SHaavard Skinnemoen "clock %u too slow; using %lu\n", 1479965ebf33SHaavard Skinnemoen clock_min, host->bus_hz / (2 * 256)); 14807d2be074SHaavard Skinnemoen clkdiv = 255; 14817d2be074SHaavard Skinnemoen } 14822c96a293SLudovic Desroches host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); 1483faf8180bSLudovic Desroches } 148404d699c3SRob Emanuele 1485965ebf33SHaavard Skinnemoen /* 1486965ebf33SHaavard Skinnemoen * WRPROOF and RDPROOF prevent overruns/underruns by 1487965ebf33SHaavard Skinnemoen * stopping the clock when the FIFO is full/empty. 1488965ebf33SHaavard Skinnemoen * This state is not expected to last for long. 1489965ebf33SHaavard Skinnemoen */ 1490796211b7SLudovic Desroches if (host->caps.has_rwproof) 14912c96a293SLudovic Desroches host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); 14927d2be074SHaavard Skinnemoen 1493796211b7SLudovic Desroches if (host->caps.has_cfg_reg) { 149499ddffd8SNicolas Ferre /* setup High Speed mode in relation with card capacity */ 149599ddffd8SNicolas Ferre if (ios->timing == MMC_TIMING_SD_HS) 14962c96a293SLudovic Desroches host->cfg_reg |= ATMCI_CFG_HSMODE; 1497965ebf33SHaavard Skinnemoen else 14982c96a293SLudovic Desroches host->cfg_reg &= ~ATMCI_CFG_HSMODE; 149999ddffd8SNicolas Ferre } 150099ddffd8SNicolas Ferre 150199ddffd8SNicolas Ferre if (list_empty(&host->queue)) { 150203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1503796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 150403fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 150599ddffd8SNicolas Ferre } else { 1506965ebf33SHaavard Skinnemoen host->need_clock_update = true; 150799ddffd8SNicolas Ferre } 1508965ebf33SHaavard Skinnemoen 1509965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1510945533b5SHaavard Skinnemoen } else { 1511965ebf33SHaavard Skinnemoen bool any_slot_active = false; 1512965ebf33SHaavard Skinnemoen 1513965ebf33SHaavard Skinnemoen spin_lock_bh(&host->lock); 1514965ebf33SHaavard Skinnemoen slot->clock = 0; 15152c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 1516965ebf33SHaavard Skinnemoen if (host->slot[i] && host->slot[i]->clock) { 1517965ebf33SHaavard Skinnemoen any_slot_active = true; 1518965ebf33SHaavard Skinnemoen break; 1519965ebf33SHaavard Skinnemoen } 1520965ebf33SHaavard Skinnemoen } 1521965ebf33SHaavard Skinnemoen if (!any_slot_active) { 152203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); 1523945533b5SHaavard Skinnemoen if (host->mode_reg) { 152403fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_MR); 1525945533b5SHaavard Skinnemoen } 1526945533b5SHaavard Skinnemoen host->mode_reg = 0; 15277d2be074SHaavard Skinnemoen } 1528965ebf33SHaavard Skinnemoen spin_unlock_bh(&host->lock); 1529965ebf33SHaavard Skinnemoen } 15307d2be074SHaavard Skinnemoen 15317d2be074SHaavard Skinnemoen switch (ios->power_mode) { 15329e7861f5SAlexandre Belloni case MMC_POWER_OFF: 15339e7861f5SAlexandre Belloni if (!IS_ERR(mmc->supply.vmmc)) 15349e7861f5SAlexandre Belloni mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 15359e7861f5SAlexandre Belloni break; 1536965ebf33SHaavard Skinnemoen case MMC_POWER_UP: 1537965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_NEED_INIT, &slot->flags); 15389e7861f5SAlexandre Belloni if (!IS_ERR(mmc->supply.vmmc)) 15399e7861f5SAlexandre Belloni mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); 1540965ebf33SHaavard Skinnemoen break; 15417d2be074SHaavard Skinnemoen default: 15427d2be074SHaavard Skinnemoen break; 15437d2be074SHaavard Skinnemoen } 15447d2be074SHaavard Skinnemoen } 15457d2be074SHaavard Skinnemoen 15467d2be074SHaavard Skinnemoen static int atmci_get_ro(struct mmc_host *mmc) 15477d2be074SHaavard Skinnemoen { 1548965ebf33SHaavard Skinnemoen int read_only = -ENOSYS; 1549965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 15507d2be074SHaavard Skinnemoen 1551965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->wp_pin)) { 1552965ebf33SHaavard Skinnemoen read_only = gpio_get_value(slot->wp_pin); 15537d2be074SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "card is %s\n", 15547d2be074SHaavard Skinnemoen read_only ? "read-only" : "read-write"); 15557d2be074SHaavard Skinnemoen } 15567d2be074SHaavard Skinnemoen 15577d2be074SHaavard Skinnemoen return read_only; 15587d2be074SHaavard Skinnemoen } 15597d2be074SHaavard Skinnemoen 1560965ebf33SHaavard Skinnemoen static int atmci_get_cd(struct mmc_host *mmc) 1561965ebf33SHaavard Skinnemoen { 1562965ebf33SHaavard Skinnemoen int present = -ENOSYS; 1563965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = mmc_priv(mmc); 1564965ebf33SHaavard Skinnemoen 1565965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 15661c1452beSJonas Larsson present = !(gpio_get_value(slot->detect_pin) ^ 15671c1452beSJonas Larsson slot->detect_is_active_high); 1568965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "card is %spresent\n", 1569965ebf33SHaavard Skinnemoen present ? "" : "not "); 1570965ebf33SHaavard Skinnemoen } 1571965ebf33SHaavard Skinnemoen 1572965ebf33SHaavard Skinnemoen return present; 1573965ebf33SHaavard Skinnemoen } 1574965ebf33SHaavard Skinnemoen 157588ff82edSAnders Grahn static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) 157688ff82edSAnders Grahn { 157788ff82edSAnders Grahn struct atmel_mci_slot *slot = mmc_priv(mmc); 157888ff82edSAnders Grahn struct atmel_mci *host = slot->host; 157988ff82edSAnders Grahn 158088ff82edSAnders Grahn if (enable) 158103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, slot->sdio_irq); 158288ff82edSAnders Grahn else 158303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, slot->sdio_irq); 158488ff82edSAnders Grahn } 158588ff82edSAnders Grahn 1586965ebf33SHaavard Skinnemoen static const struct mmc_host_ops atmci_ops = { 15877d2be074SHaavard Skinnemoen .request = atmci_request, 15887d2be074SHaavard Skinnemoen .set_ios = atmci_set_ios, 15897d2be074SHaavard Skinnemoen .get_ro = atmci_get_ro, 1590965ebf33SHaavard Skinnemoen .get_cd = atmci_get_cd, 159188ff82edSAnders Grahn .enable_sdio_irq = atmci_enable_sdio_irq, 15927d2be074SHaavard Skinnemoen }; 15937d2be074SHaavard Skinnemoen 1594965ebf33SHaavard Skinnemoen /* Called with host->lock held */ 1595965ebf33SHaavard Skinnemoen static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) 1596965ebf33SHaavard Skinnemoen __releases(&host->lock) 1597965ebf33SHaavard Skinnemoen __acquires(&host->lock) 1598965ebf33SHaavard Skinnemoen { 1599965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = NULL; 1600965ebf33SHaavard Skinnemoen struct mmc_host *prev_mmc = host->cur_slot->mmc; 1601965ebf33SHaavard Skinnemoen 1602965ebf33SHaavard Skinnemoen WARN_ON(host->cmd || host->data); 1603965ebf33SHaavard Skinnemoen 1604965ebf33SHaavard Skinnemoen /* 1605965ebf33SHaavard Skinnemoen * Update the MMC clock rate if necessary. This may be 1606965ebf33SHaavard Skinnemoen * necessary if set_ios() is called when a different slot is 160725985edcSLucas De Marchi * busy transferring data. 1608965ebf33SHaavard Skinnemoen */ 160999ddffd8SNicolas Ferre if (host->need_clock_update) { 161003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1611796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 161203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 161399ddffd8SNicolas Ferre } 1614965ebf33SHaavard Skinnemoen 1615965ebf33SHaavard Skinnemoen host->cur_slot->mrq = NULL; 1616965ebf33SHaavard Skinnemoen host->mrq = NULL; 1617965ebf33SHaavard Skinnemoen if (!list_empty(&host->queue)) { 1618965ebf33SHaavard Skinnemoen slot = list_entry(host->queue.next, 1619965ebf33SHaavard Skinnemoen struct atmel_mci_slot, queue_node); 1620965ebf33SHaavard Skinnemoen list_del(&slot->queue_node); 1621965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", 1622965ebf33SHaavard Skinnemoen mmc_hostname(slot->mmc)); 1623965ebf33SHaavard Skinnemoen host->state = STATE_SENDING_CMD; 1624965ebf33SHaavard Skinnemoen atmci_start_request(host, slot); 1625965ebf33SHaavard Skinnemoen } else { 1626965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, "list empty\n"); 1627965ebf33SHaavard Skinnemoen host->state = STATE_IDLE; 1628965ebf33SHaavard Skinnemoen } 1629965ebf33SHaavard Skinnemoen 163024011f34SLudovic Desroches del_timer(&host->timer); 163124011f34SLudovic Desroches 1632965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1633965ebf33SHaavard Skinnemoen mmc_request_done(prev_mmc, mrq); 1634965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1635965ebf33SHaavard Skinnemoen } 1636965ebf33SHaavard Skinnemoen 16377d2be074SHaavard Skinnemoen static void atmci_command_complete(struct atmel_mci *host, 1638c06ad258SHaavard Skinnemoen struct mmc_command *cmd) 16397d2be074SHaavard Skinnemoen { 1640c06ad258SHaavard Skinnemoen u32 status = host->cmd_status; 1641c06ad258SHaavard Skinnemoen 16427d2be074SHaavard Skinnemoen /* Read the response from the card (up to 16 bytes) */ 164303fc9a7fSLudovic Desroches cmd->resp[0] = atmci_readl(host, ATMCI_RSPR); 164403fc9a7fSLudovic Desroches cmd->resp[1] = atmci_readl(host, ATMCI_RSPR); 164503fc9a7fSLudovic Desroches cmd->resp[2] = atmci_readl(host, ATMCI_RSPR); 164603fc9a7fSLudovic Desroches cmd->resp[3] = atmci_readl(host, ATMCI_RSPR); 16477d2be074SHaavard Skinnemoen 16482c96a293SLudovic Desroches if (status & ATMCI_RTOE) 16497d2be074SHaavard Skinnemoen cmd->error = -ETIMEDOUT; 16502c96a293SLudovic Desroches else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE)) 16517d2be074SHaavard Skinnemoen cmd->error = -EILSEQ; 16522c96a293SLudovic Desroches else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) 16537d2be074SHaavard Skinnemoen cmd->error = -EIO; 165424011f34SLudovic Desroches else if (host->mrq->data && (host->mrq->data->blksz & 3)) { 165524011f34SLudovic Desroches if (host->caps.need_blksz_mul_4) { 165624011f34SLudovic Desroches cmd->error = -EINVAL; 165724011f34SLudovic Desroches host->need_reset = 1; 165824011f34SLudovic Desroches } 165924011f34SLudovic Desroches } else 16607d2be074SHaavard Skinnemoen cmd->error = 0; 16617d2be074SHaavard Skinnemoen } 16627d2be074SHaavard Skinnemoen 16637d2be074SHaavard Skinnemoen static void atmci_detect_change(unsigned long data) 16647d2be074SHaavard Skinnemoen { 1665965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = (struct atmel_mci_slot *)data; 1666965ebf33SHaavard Skinnemoen bool present; 1667965ebf33SHaavard Skinnemoen bool present_old; 16687d2be074SHaavard Skinnemoen 16697d2be074SHaavard Skinnemoen /* 1670965ebf33SHaavard Skinnemoen * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before 1671965ebf33SHaavard Skinnemoen * freeing the interrupt. We must not re-enable the interrupt 1672965ebf33SHaavard Skinnemoen * if it has been freed, and if we're shutting down, it 1673965ebf33SHaavard Skinnemoen * doesn't really matter whether the card is present or not. 16747d2be074SHaavard Skinnemoen */ 16757d2be074SHaavard Skinnemoen smp_rmb(); 1676965ebf33SHaavard Skinnemoen if (test_bit(ATMCI_SHUTDOWN, &slot->flags)) 16777d2be074SHaavard Skinnemoen return; 16787d2be074SHaavard Skinnemoen 1679965ebf33SHaavard Skinnemoen enable_irq(gpio_to_irq(slot->detect_pin)); 16801c1452beSJonas Larsson present = !(gpio_get_value(slot->detect_pin) ^ 16811c1452beSJonas Larsson slot->detect_is_active_high); 1682965ebf33SHaavard Skinnemoen present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags); 16837d2be074SHaavard Skinnemoen 1684965ebf33SHaavard Skinnemoen dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n", 1685965ebf33SHaavard Skinnemoen present, present_old); 16867d2be074SHaavard Skinnemoen 1687965ebf33SHaavard Skinnemoen if (present != present_old) { 1688965ebf33SHaavard Skinnemoen struct atmel_mci *host = slot->host; 1689965ebf33SHaavard Skinnemoen struct mmc_request *mrq; 1690965ebf33SHaavard Skinnemoen 1691965ebf33SHaavard Skinnemoen dev_dbg(&slot->mmc->class_dev, "card %s\n", 16927d2be074SHaavard Skinnemoen present ? "inserted" : "removed"); 16937d2be074SHaavard Skinnemoen 1694965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1695965ebf33SHaavard Skinnemoen 1696965ebf33SHaavard Skinnemoen if (!present) 1697965ebf33SHaavard Skinnemoen clear_bit(ATMCI_CARD_PRESENT, &slot->flags); 1698965ebf33SHaavard Skinnemoen else 1699965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_PRESENT, &slot->flags); 17007d2be074SHaavard Skinnemoen 17017d2be074SHaavard Skinnemoen /* Clean up queue if present */ 1702965ebf33SHaavard Skinnemoen mrq = slot->mrq; 17037d2be074SHaavard Skinnemoen if (mrq) { 1704965ebf33SHaavard Skinnemoen if (mrq == host->mrq) { 17057d2be074SHaavard Skinnemoen /* 17067d2be074SHaavard Skinnemoen * Reset controller to terminate any ongoing 17077d2be074SHaavard Skinnemoen * commands or data transfers. 17087d2be074SHaavard Skinnemoen */ 170903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 171003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); 171103fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_MR, host->mode_reg); 1712796211b7SLudovic Desroches if (host->caps.has_cfg_reg) 171303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CFG, host->cfg_reg); 17147d2be074SHaavard Skinnemoen 17157d2be074SHaavard Skinnemoen host->data = NULL; 17167d2be074SHaavard Skinnemoen host->cmd = NULL; 1717c06ad258SHaavard Skinnemoen 1718c06ad258SHaavard Skinnemoen switch (host->state) { 1719965ebf33SHaavard Skinnemoen case STATE_IDLE: 1720965ebf33SHaavard Skinnemoen break; 1721c06ad258SHaavard Skinnemoen case STATE_SENDING_CMD: 1722c06ad258SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1723f5177547SLudovic Desroches if (mrq->data) 1724f5177547SLudovic Desroches host->stop_transfer(host); 1725c06ad258SHaavard Skinnemoen break; 1726f5177547SLudovic Desroches case STATE_DATA_XFER: 1727c06ad258SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1728796211b7SLudovic Desroches host->stop_transfer(host); 1729c06ad258SHaavard Skinnemoen break; 1730f5177547SLudovic Desroches case STATE_WAITING_NOTBUSY: 1731c06ad258SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1732c06ad258SHaavard Skinnemoen break; 1733c06ad258SHaavard Skinnemoen case STATE_SENDING_STOP: 1734c06ad258SHaavard Skinnemoen mrq->stop->error = -ENOMEDIUM; 1735c06ad258SHaavard Skinnemoen break; 1736f5177547SLudovic Desroches case STATE_END_REQUEST: 1737f5177547SLudovic Desroches break; 1738c06ad258SHaavard Skinnemoen } 1739c06ad258SHaavard Skinnemoen 1740965ebf33SHaavard Skinnemoen atmci_request_end(host, mrq); 1741965ebf33SHaavard Skinnemoen } else { 1742965ebf33SHaavard Skinnemoen list_del(&slot->queue_node); 1743965ebf33SHaavard Skinnemoen mrq->cmd->error = -ENOMEDIUM; 1744965ebf33SHaavard Skinnemoen if (mrq->data) 1745965ebf33SHaavard Skinnemoen mrq->data->error = -ENOMEDIUM; 1746965ebf33SHaavard Skinnemoen if (mrq->stop) 1747965ebf33SHaavard Skinnemoen mrq->stop->error = -ENOMEDIUM; 17487d2be074SHaavard Skinnemoen 1749965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1750965ebf33SHaavard Skinnemoen mmc_request_done(slot->mmc, mrq); 1751965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1752965ebf33SHaavard Skinnemoen } 1753965ebf33SHaavard Skinnemoen } 1754965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 1755965ebf33SHaavard Skinnemoen 1756965ebf33SHaavard Skinnemoen mmc_detect_change(slot->mmc, 0); 17577d2be074SHaavard Skinnemoen } 17587d2be074SHaavard Skinnemoen } 17597d2be074SHaavard Skinnemoen 17607d2be074SHaavard Skinnemoen static void atmci_tasklet_func(unsigned long priv) 17617d2be074SHaavard Skinnemoen { 1762965ebf33SHaavard Skinnemoen struct atmel_mci *host = (struct atmel_mci *)priv; 17637d2be074SHaavard Skinnemoen struct mmc_request *mrq = host->mrq; 17647d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 1765c06ad258SHaavard Skinnemoen enum atmel_mci_state state = host->state; 1766c06ad258SHaavard Skinnemoen enum atmel_mci_state prev_state; 1767c06ad258SHaavard Skinnemoen u32 status; 1768c06ad258SHaavard Skinnemoen 1769965ebf33SHaavard Skinnemoen spin_lock(&host->lock); 1770965ebf33SHaavard Skinnemoen 1771c06ad258SHaavard Skinnemoen state = host->state; 17727d2be074SHaavard Skinnemoen 1773965ebf33SHaavard Skinnemoen dev_vdbg(&host->pdev->dev, 1774c06ad258SHaavard Skinnemoen "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", 1775c06ad258SHaavard Skinnemoen state, host->pending_events, host->completed_events, 177603fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_IMR)); 17777d2be074SHaavard Skinnemoen 1778c06ad258SHaavard Skinnemoen do { 1779c06ad258SHaavard Skinnemoen prev_state = state; 17806801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state); 1781c06ad258SHaavard Skinnemoen 1782c06ad258SHaavard Skinnemoen switch (state) { 1783965ebf33SHaavard Skinnemoen case STATE_IDLE: 1784965ebf33SHaavard Skinnemoen break; 1785965ebf33SHaavard Skinnemoen 1786c06ad258SHaavard Skinnemoen case STATE_SENDING_CMD: 1787f5177547SLudovic Desroches /* 1788f5177547SLudovic Desroches * Command has been sent, we are waiting for command 1789f5177547SLudovic Desroches * ready. Then we have three next states possible: 1790f5177547SLudovic Desroches * END_REQUEST by default, WAITING_NOTBUSY if it's a 1791f5177547SLudovic Desroches * command needing it or DATA_XFER if there is data. 1792f5177547SLudovic Desroches */ 17936801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); 1794c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1795f5177547SLudovic Desroches EVENT_CMD_RDY)) 1796c06ad258SHaavard Skinnemoen break; 1797c06ad258SHaavard Skinnemoen 17986801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed cmd ready\n"); 17997d2be074SHaavard Skinnemoen host->cmd = NULL; 1800f5177547SLudovic Desroches atmci_set_completed(host, EVENT_CMD_RDY); 1801c06ad258SHaavard Skinnemoen atmci_command_complete(host, mrq->cmd); 1802f5177547SLudovic Desroches if (mrq->data) { 18036801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 18046801c41aSLudovic Desroches "command with data transfer"); 1805f5177547SLudovic Desroches /* 1806f5177547SLudovic Desroches * If there is a command error don't start 1807f5177547SLudovic Desroches * data transfer. 1808f5177547SLudovic Desroches */ 1809f5177547SLudovic Desroches if (mrq->cmd->error) { 1810f5177547SLudovic Desroches host->stop_transfer(host); 1811f5177547SLudovic Desroches host->data = NULL; 1812f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, 1813f5177547SLudovic Desroches ATMCI_TXRDY | ATMCI_RXRDY 1814f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1815f5177547SLudovic Desroches state = STATE_END_REQUEST; 1816f5177547SLudovic Desroches } else 1817f5177547SLudovic Desroches state = STATE_DATA_XFER; 1818f5177547SLudovic Desroches } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { 18196801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 18206801c41aSLudovic Desroches "command response need waiting notbusy"); 1821f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1822f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1823f5177547SLudovic Desroches } else 1824f5177547SLudovic Desroches state = STATE_END_REQUEST; 1825c06ad258SHaavard Skinnemoen 1826f5177547SLudovic Desroches break; 1827c06ad258SHaavard Skinnemoen 1828f5177547SLudovic Desroches case STATE_DATA_XFER: 1829c06ad258SHaavard Skinnemoen if (atmci_test_and_clear_pending(host, 1830c06ad258SHaavard Skinnemoen EVENT_DATA_ERROR)) { 18316801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed data error\n"); 1832f5177547SLudovic Desroches atmci_set_completed(host, EVENT_DATA_ERROR); 1833f5177547SLudovic Desroches state = STATE_END_REQUEST; 1834c06ad258SHaavard Skinnemoen break; 18357d2be074SHaavard Skinnemoen } 18367d2be074SHaavard Skinnemoen 1837f5177547SLudovic Desroches /* 1838f5177547SLudovic Desroches * A data transfer is in progress. The event expected 1839f5177547SLudovic Desroches * to move to the next state depends of data transfer 1840f5177547SLudovic Desroches * type (PDC or DMA). Once transfer done we can move 1841f5177547SLudovic Desroches * to the next step which is WAITING_NOTBUSY in write 1842f5177547SLudovic Desroches * case and directly SENDING_STOP in read case. 1843f5177547SLudovic Desroches */ 18446801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n"); 1845c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1846c06ad258SHaavard Skinnemoen EVENT_XFER_COMPLETE)) 1847c06ad258SHaavard Skinnemoen break; 18487d2be074SHaavard Skinnemoen 18496801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, 18506801c41aSLudovic Desroches "(%s) set completed xfer complete\n", 18516801c41aSLudovic Desroches __func__); 1852c06ad258SHaavard Skinnemoen atmci_set_completed(host, EVENT_XFER_COMPLETE); 1853c06ad258SHaavard Skinnemoen 1854077d4073SLudovic Desroches if (host->caps.need_notbusy_for_read_ops || 1855077d4073SLudovic Desroches (host->data->flags & MMC_DATA_WRITE)) { 1856f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1857f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1858f5177547SLudovic Desroches } else if (host->mrq->stop) { 1859f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); 1860f5177547SLudovic Desroches atmci_send_stop_cmd(host, data); 1861f5177547SLudovic Desroches state = STATE_SENDING_STOP; 1862f5177547SLudovic Desroches } else { 1863c06ad258SHaavard Skinnemoen host->data = NULL; 18647d2be074SHaavard Skinnemoen data->bytes_xfered = data->blocks * data->blksz; 18657d2be074SHaavard Skinnemoen data->error = 0; 1866f5177547SLudovic Desroches state = STATE_END_REQUEST; 18677d2be074SHaavard Skinnemoen } 1868f5177547SLudovic Desroches break; 18697d2be074SHaavard Skinnemoen 1870f5177547SLudovic Desroches case STATE_WAITING_NOTBUSY: 1871f5177547SLudovic Desroches /* 1872f5177547SLudovic Desroches * We can be in the state for two reasons: a command 1873f5177547SLudovic Desroches * requiring waiting not busy signal (stop command 1874f5177547SLudovic Desroches * included) or a write operation. In the latest case, 1875f5177547SLudovic Desroches * we need to send a stop command. 1876f5177547SLudovic Desroches */ 18776801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: not busy?\n"); 1878f5177547SLudovic Desroches if (!atmci_test_and_clear_pending(host, 1879f5177547SLudovic Desroches EVENT_NOTBUSY)) 1880f5177547SLudovic Desroches break; 18817d2be074SHaavard Skinnemoen 18826801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set completed not busy\n"); 1883f5177547SLudovic Desroches atmci_set_completed(host, EVENT_NOTBUSY); 1884f5177547SLudovic Desroches 1885f5177547SLudovic Desroches if (host->data) { 1886f5177547SLudovic Desroches /* 1887f5177547SLudovic Desroches * For some commands such as CMD53, even if 1888f5177547SLudovic Desroches * there is data transfer, there is no stop 1889f5177547SLudovic Desroches * command to send. 1890f5177547SLudovic Desroches */ 1891f5177547SLudovic Desroches if (host->mrq->stop) { 1892f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, 1893f5177547SLudovic Desroches ATMCI_CMDRDY); 18942c96a293SLudovic Desroches atmci_send_stop_cmd(host, data); 1895f5177547SLudovic Desroches state = STATE_SENDING_STOP; 1896f5177547SLudovic Desroches } else { 1897f5177547SLudovic Desroches host->data = NULL; 1898f5177547SLudovic Desroches data->bytes_xfered = data->blocks 1899f5177547SLudovic Desroches * data->blksz; 1900f5177547SLudovic Desroches data->error = 0; 1901f5177547SLudovic Desroches state = STATE_END_REQUEST; 1902f5177547SLudovic Desroches } 1903f5177547SLudovic Desroches } else 1904f5177547SLudovic Desroches state = STATE_END_REQUEST; 1905f5177547SLudovic Desroches break; 1906c06ad258SHaavard Skinnemoen 1907c06ad258SHaavard Skinnemoen case STATE_SENDING_STOP: 1908f5177547SLudovic Desroches /* 1909f5177547SLudovic Desroches * In this state, it is important to set host->data to 1910f5177547SLudovic Desroches * NULL (which is tested in the waiting notbusy state) 1911f5177547SLudovic Desroches * in order to go to the end request state instead of 1912f5177547SLudovic Desroches * sending stop again. 1913f5177547SLudovic Desroches */ 19146801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n"); 1915c06ad258SHaavard Skinnemoen if (!atmci_test_and_clear_pending(host, 1916f5177547SLudovic Desroches EVENT_CMD_RDY)) 1917c06ad258SHaavard Skinnemoen break; 1918c06ad258SHaavard Skinnemoen 19196801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "FSM: cmd ready\n"); 1920c06ad258SHaavard Skinnemoen host->cmd = NULL; 1921f5177547SLudovic Desroches data->bytes_xfered = data->blocks * data->blksz; 1922f5177547SLudovic Desroches data->error = 0; 1923c06ad258SHaavard Skinnemoen atmci_command_complete(host, mrq->stop); 1924f5177547SLudovic Desroches if (mrq->stop->error) { 1925f5177547SLudovic Desroches host->stop_transfer(host); 1926f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, 1927f5177547SLudovic Desroches ATMCI_TXRDY | ATMCI_RXRDY 1928f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1929f5177547SLudovic Desroches state = STATE_END_REQUEST; 1930f5177547SLudovic Desroches } else { 1931f5177547SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 1932f5177547SLudovic Desroches state = STATE_WAITING_NOTBUSY; 1933f5177547SLudovic Desroches } 193441b4e9a1SNicolas Ferre host->data = NULL; 1935c06ad258SHaavard Skinnemoen break; 1936c06ad258SHaavard Skinnemoen 1937f5177547SLudovic Desroches case STATE_END_REQUEST: 1938f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY 1939f5177547SLudovic Desroches | ATMCI_DATA_ERROR_FLAGS); 1940f5177547SLudovic Desroches status = host->data_status; 1941f5177547SLudovic Desroches if (unlikely(status)) { 1942f5177547SLudovic Desroches host->stop_transfer(host); 1943f5177547SLudovic Desroches host->data = NULL; 1944fbd986cdSRodolfo Giometti if (data) { 1945f5177547SLudovic Desroches if (status & ATMCI_DTOE) { 1946f5177547SLudovic Desroches data->error = -ETIMEDOUT; 1947f5177547SLudovic Desroches } else if (status & ATMCI_DCRCE) { 1948f5177547SLudovic Desroches data->error = -EILSEQ; 1949f5177547SLudovic Desroches } else { 1950f5177547SLudovic Desroches data->error = -EIO; 1951f5177547SLudovic Desroches } 1952f5177547SLudovic Desroches } 1953fbd986cdSRodolfo Giometti } 1954f5177547SLudovic Desroches 1955f5177547SLudovic Desroches atmci_request_end(host, host->mrq); 1956f5177547SLudovic Desroches state = STATE_IDLE; 1957c06ad258SHaavard Skinnemoen break; 1958c06ad258SHaavard Skinnemoen } 1959c06ad258SHaavard Skinnemoen } while (state != prev_state); 1960c06ad258SHaavard Skinnemoen 1961c06ad258SHaavard Skinnemoen host->state = state; 1962965ebf33SHaavard Skinnemoen 1963965ebf33SHaavard Skinnemoen spin_unlock(&host->lock); 19647d2be074SHaavard Skinnemoen } 19657d2be074SHaavard Skinnemoen 19667d2be074SHaavard Skinnemoen static void atmci_read_data_pio(struct atmel_mci *host) 19677d2be074SHaavard Skinnemoen { 19687d2be074SHaavard Skinnemoen struct scatterlist *sg = host->sg; 19697d2be074SHaavard Skinnemoen void *buf = sg_virt(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)) { 19797d2be074SHaavard Skinnemoen put_unaligned(value, (u32 *)(buf + 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 buf = sg_virt(sg); 19937d2be074SHaavard Skinnemoen } 19947d2be074SHaavard Skinnemoen } else { 19957d2be074SHaavard Skinnemoen unsigned int remaining = sg->length - offset; 19967d2be074SHaavard Skinnemoen memcpy(buf + offset, &value, remaining); 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; 20067d2be074SHaavard Skinnemoen buf = sg_virt(sg); 20077d2be074SHaavard Skinnemoen memcpy(buf, (u8 *)&value + remaining, offset); 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 void *buf = sg_virt(sg); 20387d2be074SHaavard Skinnemoen unsigned int offset = host->pio_offset; 20397d2be074SHaavard Skinnemoen struct mmc_data *data = host->data; 20407d2be074SHaavard Skinnemoen u32 value; 20417d2be074SHaavard Skinnemoen u32 status; 20427d2be074SHaavard Skinnemoen unsigned int nbytes = 0; 20437d2be074SHaavard Skinnemoen 20447d2be074SHaavard Skinnemoen do { 20457d2be074SHaavard Skinnemoen if (likely(offset + 4 <= sg->length)) { 20467d2be074SHaavard Skinnemoen value = get_unaligned((u32 *)(buf + offset)); 204703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20487d2be074SHaavard Skinnemoen 20497d2be074SHaavard Skinnemoen offset += 4; 20507d2be074SHaavard Skinnemoen nbytes += 4; 20517d2be074SHaavard Skinnemoen if (offset == sg->length) { 20527d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 2053bdbc5d0cSTerry Barnaby host->sg_len--; 2054bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) 20557d2be074SHaavard Skinnemoen goto done; 20567d2be074SHaavard Skinnemoen 20577d2be074SHaavard Skinnemoen offset = 0; 20587d2be074SHaavard Skinnemoen buf = sg_virt(sg); 20597d2be074SHaavard Skinnemoen } 20607d2be074SHaavard Skinnemoen } else { 20617d2be074SHaavard Skinnemoen unsigned int remaining = sg->length - offset; 20627d2be074SHaavard Skinnemoen 20637d2be074SHaavard Skinnemoen value = 0; 20647d2be074SHaavard Skinnemoen memcpy(&value, buf + offset, remaining); 20657d2be074SHaavard Skinnemoen nbytes += remaining; 20667d2be074SHaavard Skinnemoen 20677d2be074SHaavard Skinnemoen host->sg = sg = sg_next(sg); 2068bdbc5d0cSTerry Barnaby host->sg_len--; 2069bdbc5d0cSTerry Barnaby if (!sg || !host->sg_len) { 207003fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20717d2be074SHaavard Skinnemoen goto done; 20727d2be074SHaavard Skinnemoen } 20737d2be074SHaavard Skinnemoen 20747d2be074SHaavard Skinnemoen offset = 4 - remaining; 20757d2be074SHaavard Skinnemoen buf = sg_virt(sg); 20767d2be074SHaavard Skinnemoen memcpy((u8 *)&value + remaining, buf, offset); 207703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_TDR, value); 20787d2be074SHaavard Skinnemoen nbytes += offset; 20797d2be074SHaavard Skinnemoen } 20807d2be074SHaavard Skinnemoen 208103fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 20827d2be074SHaavard Skinnemoen if (status & ATMCI_DATA_ERROR_FLAGS) { 208303fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY 20847d2be074SHaavard Skinnemoen | ATMCI_DATA_ERROR_FLAGS)); 20857d2be074SHaavard Skinnemoen host->data_status = status; 2086965ebf33SHaavard Skinnemoen data->bytes_xfered += nbytes; 2087965ebf33SHaavard Skinnemoen return; 20887d2be074SHaavard Skinnemoen } 20892c96a293SLudovic Desroches } while (status & ATMCI_TXRDY); 20907d2be074SHaavard Skinnemoen 20917d2be074SHaavard Skinnemoen host->pio_offset = offset; 20927d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 20937d2be074SHaavard Skinnemoen 20947d2be074SHaavard Skinnemoen return; 20957d2be074SHaavard Skinnemoen 20967d2be074SHaavard Skinnemoen done: 209703fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY); 209803fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); 20997d2be074SHaavard Skinnemoen data->bytes_xfered += nbytes; 2100965ebf33SHaavard Skinnemoen smp_wmb(); 2101c06ad258SHaavard Skinnemoen atmci_set_pending(host, EVENT_XFER_COMPLETE); 21027d2be074SHaavard Skinnemoen } 21037d2be074SHaavard Skinnemoen 210488ff82edSAnders Grahn static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) 210588ff82edSAnders Grahn { 210688ff82edSAnders Grahn int i; 210788ff82edSAnders Grahn 21082c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 210988ff82edSAnders Grahn struct atmel_mci_slot *slot = host->slot[i]; 211088ff82edSAnders Grahn if (slot && (status & slot->sdio_irq)) { 211188ff82edSAnders Grahn mmc_signal_sdio_irq(slot->mmc); 211288ff82edSAnders Grahn } 211388ff82edSAnders Grahn } 211488ff82edSAnders Grahn } 211588ff82edSAnders Grahn 211688ff82edSAnders Grahn 21177d2be074SHaavard Skinnemoen static irqreturn_t atmci_interrupt(int irq, void *dev_id) 21187d2be074SHaavard Skinnemoen { 2119965ebf33SHaavard Skinnemoen struct atmel_mci *host = dev_id; 21207d2be074SHaavard Skinnemoen u32 status, mask, pending; 21217d2be074SHaavard Skinnemoen unsigned int pass_count = 0; 21227d2be074SHaavard Skinnemoen 21237d2be074SHaavard Skinnemoen do { 212403fc9a7fSLudovic Desroches status = atmci_readl(host, ATMCI_SR); 212503fc9a7fSLudovic Desroches mask = atmci_readl(host, ATMCI_IMR); 21267d2be074SHaavard Skinnemoen pending = status & mask; 21277d2be074SHaavard Skinnemoen if (!pending) 21287d2be074SHaavard Skinnemoen break; 21297d2be074SHaavard Skinnemoen 21307d2be074SHaavard Skinnemoen if (pending & ATMCI_DATA_ERROR_FLAGS) { 21316801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: data error\n"); 213203fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS 2133f5177547SLudovic Desroches | ATMCI_RXRDY | ATMCI_TXRDY 2134f5177547SLudovic Desroches | ATMCI_ENDRX | ATMCI_ENDTX 2135f5177547SLudovic Desroches | ATMCI_RXBUFF | ATMCI_TXBUFE); 2136965ebf33SHaavard Skinnemoen 21377d2be074SHaavard Skinnemoen host->data_status = status; 21386801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending data error\n"); 2139965ebf33SHaavard Skinnemoen smp_wmb(); 21407d2be074SHaavard Skinnemoen atmci_set_pending(host, EVENT_DATA_ERROR); 21417d2be074SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 21427d2be074SHaavard Skinnemoen } 2143796211b7SLudovic Desroches 2144796211b7SLudovic Desroches if (pending & ATMCI_TXBUFE) { 21456801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n"); 2146796211b7SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); 21477e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); 2148796211b7SLudovic Desroches /* 2149796211b7SLudovic Desroches * We can receive this interruption before having configured 2150796211b7SLudovic Desroches * the second pdc buffer, so we need to reconfigure first and 2151796211b7SLudovic Desroches * second buffers again 2152796211b7SLudovic Desroches */ 2153796211b7SLudovic Desroches if (host->data_size) { 2154796211b7SLudovic Desroches atmci_pdc_set_both_buf(host, XFER_TRANSMIT); 21557e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); 2156796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); 2157796211b7SLudovic Desroches } else { 2158796211b7SLudovic Desroches atmci_pdc_complete(host); 2159796211b7SLudovic Desroches } 21607e8ba228SLudovic Desroches } else if (pending & ATMCI_ENDTX) { 21616801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n"); 21627e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); 21637e8ba228SLudovic Desroches 21647e8ba228SLudovic Desroches if (host->data_size) { 21657e8ba228SLudovic Desroches atmci_pdc_set_single_buf(host, 21667e8ba228SLudovic Desroches XFER_TRANSMIT, PDC_SECOND_BUF); 21677e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); 21687e8ba228SLudovic Desroches } 2169796211b7SLudovic Desroches } 2170796211b7SLudovic Desroches 21717e8ba228SLudovic Desroches if (pending & ATMCI_RXBUFF) { 21726801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n"); 21737e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); 21747e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); 21757e8ba228SLudovic Desroches /* 21767e8ba228SLudovic Desroches * We can receive this interruption before having configured 21777e8ba228SLudovic Desroches * the second pdc buffer, so we need to reconfigure first and 21787e8ba228SLudovic Desroches * second buffers again 21797e8ba228SLudovic Desroches */ 21807e8ba228SLudovic Desroches if (host->data_size) { 21817e8ba228SLudovic Desroches atmci_pdc_set_both_buf(host, XFER_RECEIVE); 21827e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); 21837e8ba228SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); 21847e8ba228SLudovic Desroches } else { 21857e8ba228SLudovic Desroches atmci_pdc_complete(host); 21867e8ba228SLudovic Desroches } 21877e8ba228SLudovic Desroches } else if (pending & ATMCI_ENDRX) { 21886801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n"); 2189796211b7SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); 2190796211b7SLudovic Desroches 2191796211b7SLudovic Desroches if (host->data_size) { 2192796211b7SLudovic Desroches atmci_pdc_set_single_buf(host, 2193796211b7SLudovic Desroches XFER_RECEIVE, PDC_SECOND_BUF); 2194796211b7SLudovic Desroches atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); 2195796211b7SLudovic Desroches } 2196796211b7SLudovic Desroches } 2197796211b7SLudovic Desroches 2198f5177547SLudovic Desroches /* 2199f5177547SLudovic Desroches * First mci IPs, so mainly the ones having pdc, have some 2200f5177547SLudovic Desroches * issues with the notbusy signal. You can't get it after 2201f5177547SLudovic Desroches * data transmission if you have not sent a stop command. 2202f5177547SLudovic Desroches * The appropriate workaround is to use the BLKE signal. 2203f5177547SLudovic Desroches */ 2204f5177547SLudovic Desroches if (pending & ATMCI_BLKE) { 22056801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: blke\n"); 2206f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_BLKE); 2207965ebf33SHaavard Skinnemoen smp_wmb(); 22086801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending notbusy\n"); 2209f5177547SLudovic Desroches atmci_set_pending(host, EVENT_NOTBUSY); 22107d2be074SHaavard Skinnemoen tasklet_schedule(&host->tasklet); 22117d2be074SHaavard Skinnemoen } 2212f5177547SLudovic Desroches 2213f5177547SLudovic Desroches if (pending & ATMCI_NOTBUSY) { 22146801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); 2215f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); 2216f5177547SLudovic Desroches smp_wmb(); 22176801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending notbusy\n"); 2218f5177547SLudovic Desroches atmci_set_pending(host, EVENT_NOTBUSY); 2219f5177547SLudovic Desroches tasklet_schedule(&host->tasklet); 2220f5177547SLudovic Desroches } 2221f5177547SLudovic Desroches 22222c96a293SLudovic Desroches if (pending & ATMCI_RXRDY) 22237d2be074SHaavard Skinnemoen atmci_read_data_pio(host); 22242c96a293SLudovic Desroches if (pending & ATMCI_TXRDY) 22257d2be074SHaavard Skinnemoen atmci_write_data_pio(host); 22267d2be074SHaavard Skinnemoen 2227f5177547SLudovic Desroches if (pending & ATMCI_CMDRDY) { 22286801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n"); 2229f5177547SLudovic Desroches atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); 2230f5177547SLudovic Desroches host->cmd_status = status; 2231f5177547SLudovic Desroches smp_wmb(); 22326801c41aSLudovic Desroches dev_dbg(&host->pdev->dev, "set pending cmd rdy\n"); 2233f5177547SLudovic Desroches atmci_set_pending(host, EVENT_CMD_RDY); 2234f5177547SLudovic Desroches tasklet_schedule(&host->tasklet); 2235f5177547SLudovic Desroches } 223688ff82edSAnders Grahn 22372c96a293SLudovic Desroches if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) 223888ff82edSAnders Grahn atmci_sdio_interrupt(host, status); 223988ff82edSAnders Grahn 22407d2be074SHaavard Skinnemoen } while (pass_count++ < 5); 22417d2be074SHaavard Skinnemoen 22427d2be074SHaavard Skinnemoen return pass_count ? IRQ_HANDLED : IRQ_NONE; 22437d2be074SHaavard Skinnemoen } 22447d2be074SHaavard Skinnemoen 22457d2be074SHaavard Skinnemoen static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) 22467d2be074SHaavard Skinnemoen { 2247965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot = dev_id; 22487d2be074SHaavard Skinnemoen 22497d2be074SHaavard Skinnemoen /* 22507d2be074SHaavard Skinnemoen * Disable interrupts until the pin has stabilized and check 22517d2be074SHaavard Skinnemoen * the state then. Use mod_timer() since we may be in the 22527d2be074SHaavard Skinnemoen * middle of the timer routine when this interrupt triggers. 22537d2be074SHaavard Skinnemoen */ 22547d2be074SHaavard Skinnemoen disable_irq_nosync(irq); 2255965ebf33SHaavard Skinnemoen mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20)); 22567d2be074SHaavard Skinnemoen 22577d2be074SHaavard Skinnemoen return IRQ_HANDLED; 22587d2be074SHaavard Skinnemoen } 22597d2be074SHaavard Skinnemoen 2260ab050b92Sludovic.desroches@atmel.com static int atmci_init_slot(struct atmel_mci *host, 2261965ebf33SHaavard Skinnemoen struct mci_slot_pdata *slot_data, unsigned int id, 226288ff82edSAnders Grahn u32 sdc_reg, u32 sdio_irq) 2263965ebf33SHaavard Skinnemoen { 2264965ebf33SHaavard Skinnemoen struct mmc_host *mmc; 2265965ebf33SHaavard Skinnemoen struct atmel_mci_slot *slot; 2266965ebf33SHaavard Skinnemoen 2267965ebf33SHaavard Skinnemoen mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev); 2268965ebf33SHaavard Skinnemoen if (!mmc) 2269965ebf33SHaavard Skinnemoen return -ENOMEM; 2270965ebf33SHaavard Skinnemoen 2271965ebf33SHaavard Skinnemoen slot = mmc_priv(mmc); 2272965ebf33SHaavard Skinnemoen slot->mmc = mmc; 2273965ebf33SHaavard Skinnemoen slot->host = host; 2274965ebf33SHaavard Skinnemoen slot->detect_pin = slot_data->detect_pin; 2275965ebf33SHaavard Skinnemoen slot->wp_pin = slot_data->wp_pin; 22761c1452beSJonas Larsson slot->detect_is_active_high = slot_data->detect_is_active_high; 2277965ebf33SHaavard Skinnemoen slot->sdc_reg = sdc_reg; 227888ff82edSAnders Grahn slot->sdio_irq = sdio_irq; 2279965ebf33SHaavard Skinnemoen 2280e919fd20SLudovic Desroches dev_dbg(&mmc->class_dev, 2281e919fd20SLudovic Desroches "slot[%u]: bus_width=%u, detect_pin=%d, " 2282e919fd20SLudovic Desroches "detect_is_active_high=%s, wp_pin=%d\n", 2283e919fd20SLudovic Desroches id, slot_data->bus_width, slot_data->detect_pin, 2284e919fd20SLudovic Desroches slot_data->detect_is_active_high ? "true" : "false", 2285e919fd20SLudovic Desroches slot_data->wp_pin); 2286e919fd20SLudovic Desroches 2287965ebf33SHaavard Skinnemoen mmc->ops = &atmci_ops; 2288965ebf33SHaavard Skinnemoen mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); 2289965ebf33SHaavard Skinnemoen mmc->f_max = host->bus_hz / 2; 2290965ebf33SHaavard Skinnemoen mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 229188ff82edSAnders Grahn if (sdio_irq) 229288ff82edSAnders Grahn mmc->caps |= MMC_CAP_SDIO_IRQ; 2293796211b7SLudovic Desroches if (host->caps.has_highspeed) 229499ddffd8SNicolas Ferre mmc->caps |= MMC_CAP_SD_HIGHSPEED; 22957a90dcc2SLudovic Desroches /* 22967a90dcc2SLudovic Desroches * Without the read/write proof capability, it is strongly suggested to 22977a90dcc2SLudovic Desroches * use only one bit for data to prevent fifo underruns and overruns 22987a90dcc2SLudovic Desroches * which will corrupt data. 22997a90dcc2SLudovic Desroches */ 23007a90dcc2SLudovic Desroches if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) 2301965ebf33SHaavard Skinnemoen mmc->caps |= MMC_CAP_4_BIT_DATA; 2302965ebf33SHaavard Skinnemoen 23037a90dcc2SLudovic Desroches if (atmci_get_version(host) < 0x200) { 23047a90dcc2SLudovic Desroches mmc->max_segs = 256; 23057a90dcc2SLudovic Desroches mmc->max_blk_size = 4095; 23067a90dcc2SLudovic Desroches mmc->max_blk_count = 256; 23077a90dcc2SLudovic Desroches mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 23087a90dcc2SLudovic Desroches mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs; 23097a90dcc2SLudovic Desroches } else { 2310a36274e0SMartin K. Petersen mmc->max_segs = 64; 2311965ebf33SHaavard Skinnemoen mmc->max_req_size = 32768 * 512; 2312965ebf33SHaavard Skinnemoen mmc->max_blk_size = 32768; 2313965ebf33SHaavard Skinnemoen mmc->max_blk_count = 512; 23147a90dcc2SLudovic Desroches } 2315965ebf33SHaavard Skinnemoen 2316965ebf33SHaavard Skinnemoen /* Assume card is present initially */ 2317965ebf33SHaavard Skinnemoen set_bit(ATMCI_CARD_PRESENT, &slot->flags); 2318965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 23197bca646eSPramod Gurav if (devm_gpio_request(&host->pdev->dev, slot->detect_pin, 23207bca646eSPramod Gurav "mmc_detect")) { 2321965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "no detect pin available\n"); 2322965ebf33SHaavard Skinnemoen slot->detect_pin = -EBUSY; 23231c1452beSJonas Larsson } else if (gpio_get_value(slot->detect_pin) ^ 23241c1452beSJonas Larsson slot->detect_is_active_high) { 2325965ebf33SHaavard Skinnemoen clear_bit(ATMCI_CARD_PRESENT, &slot->flags); 2326965ebf33SHaavard Skinnemoen } 2327965ebf33SHaavard Skinnemoen } 2328965ebf33SHaavard Skinnemoen 232976d55564STimo Kokkonen if (!gpio_is_valid(slot->detect_pin)) { 233076d55564STimo Kokkonen if (slot_data->non_removable) 233176d55564STimo Kokkonen mmc->caps |= MMC_CAP_NONREMOVABLE; 233276d55564STimo Kokkonen else 2333965ebf33SHaavard Skinnemoen mmc->caps |= MMC_CAP_NEEDS_POLL; 233476d55564STimo Kokkonen } 2335965ebf33SHaavard Skinnemoen 2336965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->wp_pin)) { 23377bca646eSPramod Gurav if (devm_gpio_request(&host->pdev->dev, slot->wp_pin, 23387bca646eSPramod Gurav "mmc_wp")) { 2339965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, "no WP pin available\n"); 2340965ebf33SHaavard Skinnemoen slot->wp_pin = -EBUSY; 2341965ebf33SHaavard Skinnemoen } 2342965ebf33SHaavard Skinnemoen } 2343965ebf33SHaavard Skinnemoen 2344965ebf33SHaavard Skinnemoen host->slot[id] = slot; 23459e7861f5SAlexandre Belloni mmc_regulator_get_supply(mmc); 2346965ebf33SHaavard Skinnemoen mmc_add_host(mmc); 2347965ebf33SHaavard Skinnemoen 2348965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 2349965ebf33SHaavard Skinnemoen int ret; 2350965ebf33SHaavard Skinnemoen 2351965ebf33SHaavard Skinnemoen setup_timer(&slot->detect_timer, atmci_detect_change, 2352965ebf33SHaavard Skinnemoen (unsigned long)slot); 2353965ebf33SHaavard Skinnemoen 2354965ebf33SHaavard Skinnemoen ret = request_irq(gpio_to_irq(slot->detect_pin), 2355965ebf33SHaavard Skinnemoen atmci_detect_interrupt, 2356965ebf33SHaavard Skinnemoen IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 2357965ebf33SHaavard Skinnemoen "mmc-detect", slot); 2358965ebf33SHaavard Skinnemoen if (ret) { 2359965ebf33SHaavard Skinnemoen dev_dbg(&mmc->class_dev, 2360965ebf33SHaavard Skinnemoen "could not request IRQ %d for detect pin\n", 2361965ebf33SHaavard Skinnemoen gpio_to_irq(slot->detect_pin)); 2362965ebf33SHaavard Skinnemoen slot->detect_pin = -EBUSY; 2363965ebf33SHaavard Skinnemoen } 2364965ebf33SHaavard Skinnemoen } 2365965ebf33SHaavard Skinnemoen 2366965ebf33SHaavard Skinnemoen atmci_init_debugfs(slot); 2367965ebf33SHaavard Skinnemoen 2368965ebf33SHaavard Skinnemoen return 0; 2369965ebf33SHaavard Skinnemoen } 2370965ebf33SHaavard Skinnemoen 23715fef365bSArnd Bergmann static void atmci_cleanup_slot(struct atmel_mci_slot *slot, 2372965ebf33SHaavard Skinnemoen unsigned int id) 2373965ebf33SHaavard Skinnemoen { 2374965ebf33SHaavard Skinnemoen /* Debugfs stuff is cleaned up by mmc core */ 2375965ebf33SHaavard Skinnemoen 2376965ebf33SHaavard Skinnemoen set_bit(ATMCI_SHUTDOWN, &slot->flags); 2377965ebf33SHaavard Skinnemoen smp_wmb(); 2378965ebf33SHaavard Skinnemoen 2379965ebf33SHaavard Skinnemoen mmc_remove_host(slot->mmc); 2380965ebf33SHaavard Skinnemoen 2381965ebf33SHaavard Skinnemoen if (gpio_is_valid(slot->detect_pin)) { 2382965ebf33SHaavard Skinnemoen int pin = slot->detect_pin; 2383965ebf33SHaavard Skinnemoen 2384965ebf33SHaavard Skinnemoen free_irq(gpio_to_irq(pin), slot); 2385965ebf33SHaavard Skinnemoen del_timer_sync(&slot->detect_timer); 2386965ebf33SHaavard Skinnemoen } 2387965ebf33SHaavard Skinnemoen 2388965ebf33SHaavard Skinnemoen slot->host->slot[id] = NULL; 2389965ebf33SHaavard Skinnemoen mmc_free_host(slot->mmc); 2390965ebf33SHaavard Skinnemoen } 2391965ebf33SHaavard Skinnemoen 2392467e081dSludovic.desroches@atmel.com static int atmci_configure_dma(struct atmel_mci *host) 23932635d1baSNicolas Ferre { 2394467e081dSludovic.desroches@atmel.com host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev, 2395467e081dSludovic.desroches@atmel.com "rxtx"); 239674843787SMans Rullgard 239774843787SMans Rullgard if (PTR_ERR(host->dma.chan) == -ENODEV) { 239874843787SMans Rullgard struct mci_platform_data *pdata = host->pdev->dev.platform_data; 239974843787SMans Rullgard dma_cap_mask_t mask; 240074843787SMans Rullgard 240193c77d29SBrent Taylor if (!pdata || !pdata->dma_filter) 240274843787SMans Rullgard return -ENODEV; 240374843787SMans Rullgard 240474843787SMans Rullgard dma_cap_zero(mask); 240574843787SMans Rullgard dma_cap_set(DMA_SLAVE, mask); 240674843787SMans Rullgard 240774843787SMans Rullgard host->dma.chan = dma_request_channel(mask, pdata->dma_filter, 240874843787SMans Rullgard pdata->dma_slave); 240974843787SMans Rullgard if (!host->dma.chan) 241074843787SMans Rullgard host->dma.chan = ERR_PTR(-ENODEV); 241174843787SMans Rullgard } 241274843787SMans Rullgard 2413467e081dSludovic.desroches@atmel.com if (IS_ERR(host->dma.chan)) 2414467e081dSludovic.desroches@atmel.com return PTR_ERR(host->dma.chan); 24152635d1baSNicolas Ferre 2416467e081dSludovic.desroches@atmel.com dev_info(&host->pdev->dev, "using %s for DMA transfers\n", 241774791a2dSNicolas Ferre dma_chan_name(host->dma.chan)); 2418e2b35f3dSViresh Kumar 2419e2b35f3dSViresh Kumar host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; 2420e2b35f3dSViresh Kumar host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 2421e2b35f3dSViresh Kumar host->dma_conf.src_maxburst = 1; 2422e2b35f3dSViresh Kumar host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; 2423e2b35f3dSViresh Kumar host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 2424e2b35f3dSViresh Kumar host->dma_conf.dst_maxburst = 1; 2425e2b35f3dSViresh Kumar host->dma_conf.device_fc = false; 2426467e081dSludovic.desroches@atmel.com 2427467e081dSludovic.desroches@atmel.com return 0; 24282635d1baSNicolas Ferre } 2429796211b7SLudovic Desroches 2430796211b7SLudovic Desroches /* 2431796211b7SLudovic Desroches * HSMCI (High Speed MCI) module is not fully compatible with MCI module. 2432796211b7SLudovic Desroches * HSMCI provides DMA support and a new config register but no more supports 2433796211b7SLudovic Desroches * PDC. 2434796211b7SLudovic Desroches */ 2435ab050b92Sludovic.desroches@atmel.com static void atmci_get_cap(struct atmel_mci *host) 2436796211b7SLudovic Desroches { 2437796211b7SLudovic Desroches unsigned int version; 2438796211b7SLudovic Desroches 2439796211b7SLudovic Desroches version = atmci_get_version(host); 2440796211b7SLudovic Desroches dev_info(&host->pdev->dev, 2441796211b7SLudovic Desroches "version: 0x%x\n", version); 2442796211b7SLudovic Desroches 2443ccdfe612SHein_Tibosch host->caps.has_dma_conf_reg = 0; 2444ef4b160fSAndy Shevchenko host->caps.has_pdc = 1; 2445796211b7SLudovic Desroches host->caps.has_cfg_reg = 0; 2446796211b7SLudovic Desroches host->caps.has_cstor_reg = 0; 2447796211b7SLudovic Desroches host->caps.has_highspeed = 0; 2448796211b7SLudovic Desroches host->caps.has_rwproof = 0; 2449faf8180bSLudovic Desroches host->caps.has_odd_clk_div = 0; 245024011f34SLudovic Desroches host->caps.has_bad_data_ordering = 1; 245124011f34SLudovic Desroches host->caps.need_reset_after_xfer = 1; 245224011f34SLudovic Desroches host->caps.need_blksz_mul_4 = 1; 2453077d4073SLudovic Desroches host->caps.need_notbusy_for_read_ops = 0; 2454796211b7SLudovic Desroches 2455796211b7SLudovic Desroches /* keep only major version number */ 2456796211b7SLudovic Desroches switch (version & 0xf00) { 2457215ba399SNicolas Ferre case 0x600: 2458796211b7SLudovic Desroches case 0x500: 2459faf8180bSLudovic Desroches host->caps.has_odd_clk_div = 1; 2460faf8180bSLudovic Desroches case 0x400: 2461faf8180bSLudovic Desroches case 0x300: 2462ccdfe612SHein_Tibosch host->caps.has_dma_conf_reg = 1; 2463faf8180bSLudovic Desroches host->caps.has_pdc = 0; 2464796211b7SLudovic Desroches host->caps.has_cfg_reg = 1; 2465796211b7SLudovic Desroches host->caps.has_cstor_reg = 1; 2466796211b7SLudovic Desroches host->caps.has_highspeed = 1; 2467faf8180bSLudovic Desroches case 0x200: 2468796211b7SLudovic Desroches host->caps.has_rwproof = 1; 246924011f34SLudovic Desroches host->caps.need_blksz_mul_4 = 0; 2470077d4073SLudovic Desroches host->caps.need_notbusy_for_read_ops = 1; 2471faf8180bSLudovic Desroches case 0x100: 247224011f34SLudovic Desroches host->caps.has_bad_data_ordering = 0; 247324011f34SLudovic Desroches host->caps.need_reset_after_xfer = 0; 247424011f34SLudovic Desroches case 0x0: 2475796211b7SLudovic Desroches break; 2476796211b7SLudovic Desroches default: 2477faf8180bSLudovic Desroches host->caps.has_pdc = 0; 2478796211b7SLudovic Desroches dev_warn(&host->pdev->dev, 2479796211b7SLudovic Desroches "Unmanaged mci version, set minimum capabilities\n"); 2480796211b7SLudovic Desroches break; 2481796211b7SLudovic Desroches } 2482796211b7SLudovic Desroches } 248374465b4fSDan Williams 2484ab050b92Sludovic.desroches@atmel.com static int atmci_probe(struct platform_device *pdev) 24857d2be074SHaavard Skinnemoen { 24867d2be074SHaavard Skinnemoen struct mci_platform_data *pdata; 24877d2be074SHaavard Skinnemoen struct atmel_mci *host; 24887d2be074SHaavard Skinnemoen struct resource *regs; 2489965ebf33SHaavard Skinnemoen unsigned int nr_slots; 24907d2be074SHaavard Skinnemoen int irq; 2491528bc780SPramod Gurav int ret, i; 24927d2be074SHaavard Skinnemoen 24937d2be074SHaavard Skinnemoen regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 24947d2be074SHaavard Skinnemoen if (!regs) 24957d2be074SHaavard Skinnemoen return -ENXIO; 24967d2be074SHaavard Skinnemoen pdata = pdev->dev.platform_data; 2497e919fd20SLudovic Desroches if (!pdata) { 2498e919fd20SLudovic Desroches pdata = atmci_of_init(pdev); 2499e919fd20SLudovic Desroches if (IS_ERR(pdata)) { 2500e919fd20SLudovic Desroches dev_err(&pdev->dev, "platform data not available\n"); 2501e919fd20SLudovic Desroches return PTR_ERR(pdata); 2502e919fd20SLudovic Desroches } 2503e919fd20SLudovic Desroches } 2504e919fd20SLudovic Desroches 25057d2be074SHaavard Skinnemoen irq = platform_get_irq(pdev, 0); 25067d2be074SHaavard Skinnemoen if (irq < 0) 25077d2be074SHaavard Skinnemoen return irq; 25087d2be074SHaavard Skinnemoen 25097bca646eSPramod Gurav host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); 2510965ebf33SHaavard Skinnemoen if (!host) 25117d2be074SHaavard Skinnemoen return -ENOMEM; 25127d2be074SHaavard Skinnemoen 25137d2be074SHaavard Skinnemoen host->pdev = pdev; 2514965ebf33SHaavard Skinnemoen spin_lock_init(&host->lock); 2515965ebf33SHaavard Skinnemoen INIT_LIST_HEAD(&host->queue); 25167d2be074SHaavard Skinnemoen 25177bca646eSPramod Gurav host->mck = devm_clk_get(&pdev->dev, "mci_clk"); 25187bca646eSPramod Gurav if (IS_ERR(host->mck)) 25197bca646eSPramod Gurav return PTR_ERR(host->mck); 25207d2be074SHaavard Skinnemoen 25217bca646eSPramod Gurav host->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); 25227d2be074SHaavard Skinnemoen if (!host->regs) 25237bca646eSPramod Gurav return -ENOMEM; 25247d2be074SHaavard Skinnemoen 2525b3894f26SBoris BREZILLON ret = clk_prepare_enable(host->mck); 2526b3894f26SBoris BREZILLON if (ret) 25277bca646eSPramod Gurav return ret; 25287bca646eSPramod Gurav 252903fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); 25307d2be074SHaavard Skinnemoen host->bus_hz = clk_get_rate(host->mck); 25317d2be074SHaavard Skinnemoen 25327d2be074SHaavard Skinnemoen host->mapbase = regs->start; 25337d2be074SHaavard Skinnemoen 2534965ebf33SHaavard Skinnemoen tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host); 25357d2be074SHaavard Skinnemoen 253689c8aa20SKay Sievers ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); 2537ae552ab0SWenyou Yang if (ret) { 2538ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 25397bca646eSPramod Gurav return ret; 2540ae552ab0SWenyou Yang } 25417d2be074SHaavard Skinnemoen 2542796211b7SLudovic Desroches /* Get MCI capabilities and set operations according to it */ 2543796211b7SLudovic Desroches atmci_get_cap(host); 2544467e081dSludovic.desroches@atmel.com ret = atmci_configure_dma(host); 2545467e081dSludovic.desroches@atmel.com if (ret == -EPROBE_DEFER) 2546467e081dSludovic.desroches@atmel.com goto err_dma_probe_defer; 2547467e081dSludovic.desroches@atmel.com if (ret == 0) { 2548796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data_dma; 2549796211b7SLudovic Desroches host->submit_data = &atmci_submit_data_dma; 2550796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer_dma; 2551796211b7SLudovic Desroches } else if (host->caps.has_pdc) { 2552796211b7SLudovic Desroches dev_info(&pdev->dev, "using PDC\n"); 2553796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data_pdc; 2554796211b7SLudovic Desroches host->submit_data = &atmci_submit_data_pdc; 2555796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer_pdc; 2556796211b7SLudovic Desroches } else { 2557ef878198SLudovic Desroches dev_info(&pdev->dev, "using PIO\n"); 2558796211b7SLudovic Desroches host->prepare_data = &atmci_prepare_data; 2559796211b7SLudovic Desroches host->submit_data = &atmci_submit_data; 2560796211b7SLudovic Desroches host->stop_transfer = &atmci_stop_transfer; 2561796211b7SLudovic Desroches } 2562796211b7SLudovic Desroches 25637d2be074SHaavard Skinnemoen platform_set_drvdata(pdev, host); 25647d2be074SHaavard Skinnemoen 2565b87cc1b5SLudovic Desroches setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); 2566b87cc1b5SLudovic Desroches 2567ae552ab0SWenyou Yang pm_runtime_get_noresume(&pdev->dev); 2568ae552ab0SWenyou Yang pm_runtime_set_active(&pdev->dev); 2569ae552ab0SWenyou Yang pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY); 2570ae552ab0SWenyou Yang pm_runtime_use_autosuspend(&pdev->dev); 2571ae552ab0SWenyou Yang pm_runtime_enable(&pdev->dev); 2572ae552ab0SWenyou Yang 2573965ebf33SHaavard Skinnemoen /* We need at least one slot to succeed */ 2574965ebf33SHaavard Skinnemoen nr_slots = 0; 2575965ebf33SHaavard Skinnemoen ret = -ENODEV; 2576965ebf33SHaavard Skinnemoen if (pdata->slot[0].bus_width) { 2577965ebf33SHaavard Skinnemoen ret = atmci_init_slot(host, &pdata->slot[0], 25782c96a293SLudovic Desroches 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); 25797a90dcc2SLudovic Desroches if (!ret) { 2580965ebf33SHaavard Skinnemoen nr_slots++; 25817a90dcc2SLudovic Desroches host->buf_size = host->slot[0]->mmc->max_req_size; 25827a90dcc2SLudovic Desroches } 25837d2be074SHaavard Skinnemoen } 2584965ebf33SHaavard Skinnemoen if (pdata->slot[1].bus_width) { 2585965ebf33SHaavard Skinnemoen ret = atmci_init_slot(host, &pdata->slot[1], 25862c96a293SLudovic Desroches 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); 25877a90dcc2SLudovic Desroches if (!ret) { 2588965ebf33SHaavard Skinnemoen nr_slots++; 25897a90dcc2SLudovic Desroches if (host->slot[1]->mmc->max_req_size > host->buf_size) 25907a90dcc2SLudovic Desroches host->buf_size = 25917a90dcc2SLudovic Desroches host->slot[1]->mmc->max_req_size; 25927a90dcc2SLudovic Desroches } 25937d2be074SHaavard Skinnemoen } 25947d2be074SHaavard Skinnemoen 259504d699c3SRob Emanuele if (!nr_slots) { 259604d699c3SRob Emanuele dev_err(&pdev->dev, "init failed: no slot defined\n"); 2597965ebf33SHaavard Skinnemoen goto err_init_slot; 259804d699c3SRob Emanuele } 25997d2be074SHaavard Skinnemoen 26007a90dcc2SLudovic Desroches if (!host->caps.has_rwproof) { 26017a90dcc2SLudovic Desroches host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, 26027a90dcc2SLudovic Desroches &host->buf_phys_addr, 26037a90dcc2SLudovic Desroches GFP_KERNEL); 26047a90dcc2SLudovic Desroches if (!host->buffer) { 26057a90dcc2SLudovic Desroches ret = -ENOMEM; 26067a90dcc2SLudovic Desroches dev_err(&pdev->dev, "buffer allocation failed\n"); 2607528bc780SPramod Gurav goto err_dma_alloc; 26087a90dcc2SLudovic Desroches } 26097a90dcc2SLudovic Desroches } 26107a90dcc2SLudovic Desroches 2611965ebf33SHaavard Skinnemoen dev_info(&pdev->dev, 2612965ebf33SHaavard Skinnemoen "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", 2613965ebf33SHaavard Skinnemoen host->mapbase, irq, nr_slots); 2614deec9ae3SHaavard Skinnemoen 2615ae552ab0SWenyou Yang pm_runtime_mark_last_busy(&host->pdev->dev); 2616ae552ab0SWenyou Yang pm_runtime_put_autosuspend(&pdev->dev); 2617ae552ab0SWenyou Yang 26187d2be074SHaavard Skinnemoen return 0; 26197d2be074SHaavard Skinnemoen 2620528bc780SPramod Gurav err_dma_alloc: 2621528bc780SPramod Gurav for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 2622528bc780SPramod Gurav if (host->slot[i]) 2623528bc780SPramod Gurav atmci_cleanup_slot(host->slot[i], i); 2624528bc780SPramod Gurav } 2625965ebf33SHaavard Skinnemoen err_init_slot: 2626ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2627ae552ab0SWenyou Yang 2628ae552ab0SWenyou Yang pm_runtime_disable(&pdev->dev); 2629ae552ab0SWenyou Yang pm_runtime_put_noidle(&pdev->dev); 2630ae552ab0SWenyou Yang 2631528bc780SPramod Gurav del_timer_sync(&host->timer); 2632467e081dSludovic.desroches@atmel.com if (!IS_ERR(host->dma.chan)) 263374465b4fSDan Williams dma_release_channel(host->dma.chan); 2634467e081dSludovic.desroches@atmel.com err_dma_probe_defer: 2635965ebf33SHaavard Skinnemoen free_irq(irq, host); 26367d2be074SHaavard Skinnemoen return ret; 26377d2be074SHaavard Skinnemoen } 26387d2be074SHaavard Skinnemoen 2639ab050b92Sludovic.desroches@atmel.com static int atmci_remove(struct platform_device *pdev) 26407d2be074SHaavard Skinnemoen { 26417d2be074SHaavard Skinnemoen struct atmel_mci *host = platform_get_drvdata(pdev); 2642965ebf33SHaavard Skinnemoen unsigned int i; 26437d2be074SHaavard Skinnemoen 2644ae552ab0SWenyou Yang pm_runtime_get_sync(&pdev->dev); 2645ae552ab0SWenyou Yang 26467a90dcc2SLudovic Desroches if (host->buffer) 26477a90dcc2SLudovic Desroches dma_free_coherent(&pdev->dev, host->buf_size, 26487a90dcc2SLudovic Desroches host->buffer, host->buf_phys_addr); 26497a90dcc2SLudovic Desroches 26502c96a293SLudovic Desroches for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 2651965ebf33SHaavard Skinnemoen if (host->slot[i]) 2652965ebf33SHaavard Skinnemoen atmci_cleanup_slot(host->slot[i], i); 26537d2be074SHaavard Skinnemoen } 26547d2be074SHaavard Skinnemoen 265503fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_IDR, ~0UL); 265603fc9a7fSLudovic Desroches atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); 265703fc9a7fSLudovic Desroches atmci_readl(host, ATMCI_SR); 26587d2be074SHaavard Skinnemoen 2659528bc780SPramod Gurav del_timer_sync(&host->timer); 2660467e081dSludovic.desroches@atmel.com if (!IS_ERR(host->dma.chan)) 266174465b4fSDan Williams dma_release_channel(host->dma.chan); 266265e8b083SHaavard Skinnemoen 2663965ebf33SHaavard Skinnemoen free_irq(platform_get_irq(pdev, 0), host); 26647d2be074SHaavard Skinnemoen 2665ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2666ae552ab0SWenyou Yang 2667ae552ab0SWenyou Yang pm_runtime_disable(&pdev->dev); 2668ae552ab0SWenyou Yang pm_runtime_put_noidle(&pdev->dev); 2669ae552ab0SWenyou Yang 26707d2be074SHaavard Skinnemoen return 0; 26717d2be074SHaavard Skinnemoen } 26727d2be074SHaavard Skinnemoen 2673ae552ab0SWenyou Yang #ifdef CONFIG_PM 2674ae552ab0SWenyou Yang static int atmci_runtime_suspend(struct device *dev) 2675ae552ab0SWenyou Yang { 2676ae552ab0SWenyou Yang struct atmel_mci *host = dev_get_drvdata(dev); 2677ae552ab0SWenyou Yang 2678ae552ab0SWenyou Yang clk_disable_unprepare(host->mck); 2679ae552ab0SWenyou Yang 2680b5b64fa6SWenyou Yang pinctrl_pm_select_sleep_state(dev); 2681b5b64fa6SWenyou Yang 2682ae552ab0SWenyou Yang return 0; 2683ae552ab0SWenyou Yang } 2684ae552ab0SWenyou Yang 2685ae552ab0SWenyou Yang static int atmci_runtime_resume(struct device *dev) 2686ae552ab0SWenyou Yang { 2687ae552ab0SWenyou Yang struct atmel_mci *host = dev_get_drvdata(dev); 2688ae552ab0SWenyou Yang 2689b5b64fa6SWenyou Yang pinctrl_pm_select_default_state(dev); 2690b5b64fa6SWenyou Yang 2691ae552ab0SWenyou Yang return clk_prepare_enable(host->mck); 2692ae552ab0SWenyou Yang } 2693ae552ab0SWenyou Yang #endif 2694ae552ab0SWenyou Yang 2695ae552ab0SWenyou Yang static const struct dev_pm_ops atmci_dev_pm_ops = { 2696ae552ab0SWenyou Yang SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 2697ae552ab0SWenyou Yang pm_runtime_force_resume) 2698c3cb6ba4SLudovic Desroches SET_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL) 2699ae552ab0SWenyou Yang }; 2700ae552ab0SWenyou Yang 27017d2be074SHaavard Skinnemoen static struct platform_driver atmci_driver = { 27025e0fe897Sludovic.desroches@atmel.com .probe = atmci_probe, 2703ab050b92Sludovic.desroches@atmel.com .remove = atmci_remove, 27047d2be074SHaavard Skinnemoen .driver = { 27057d2be074SHaavard Skinnemoen .name = "atmel_mci", 2706e919fd20SLudovic Desroches .of_match_table = of_match_ptr(atmci_dt_ids), 2707ae552ab0SWenyou Yang .pm = &atmci_dev_pm_ops, 27087d2be074SHaavard Skinnemoen }, 27097d2be074SHaavard Skinnemoen }; 27105e0fe897Sludovic.desroches@atmel.com module_platform_driver(atmci_driver); 27117d2be074SHaavard Skinnemoen 27127d2be074SHaavard Skinnemoen MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); 2713e05503efSJean Delvare MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); 27147d2be074SHaavard Skinnemoen MODULE_LICENSE("GPL v2"); 2715