161bfbdb8SLars-Peter Clausen /* 261bfbdb8SLars-Peter Clausen * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 361bfbdb8SLars-Peter Clausen * JZ4740 SD/MMC controller driver 461bfbdb8SLars-Peter Clausen * 561bfbdb8SLars-Peter Clausen * This program is free software; you can redistribute it and/or modify it 661bfbdb8SLars-Peter Clausen * under the terms of the GNU General Public License as published by the 761bfbdb8SLars-Peter Clausen * Free Software Foundation; either version 2 of the License, or (at your 861bfbdb8SLars-Peter Clausen * option) any later version. 961bfbdb8SLars-Peter Clausen * 1061bfbdb8SLars-Peter Clausen * You should have received a copy of the GNU General Public License along 1161bfbdb8SLars-Peter Clausen * with this program; if not, write to the Free Software Foundation, Inc., 1261bfbdb8SLars-Peter Clausen * 675 Mass Ave, Cambridge, MA 02139, USA. 1361bfbdb8SLars-Peter Clausen * 1461bfbdb8SLars-Peter Clausen */ 1561bfbdb8SLars-Peter Clausen 1661bfbdb8SLars-Peter Clausen #include <linux/mmc/host.h> 1758e300afSLars-Peter Clausen #include <linux/mmc/slot-gpio.h> 183119cbdaSJamie Iles #include <linux/err.h> 1961bfbdb8SLars-Peter Clausen #include <linux/io.h> 2061bfbdb8SLars-Peter Clausen #include <linux/irq.h> 2161bfbdb8SLars-Peter Clausen #include <linux/interrupt.h> 2261bfbdb8SLars-Peter Clausen #include <linux/module.h> 2361bfbdb8SLars-Peter Clausen #include <linux/platform_device.h> 2461bfbdb8SLars-Peter Clausen #include <linux/delay.h> 2561bfbdb8SLars-Peter Clausen #include <linux/scatterlist.h> 2661bfbdb8SLars-Peter Clausen #include <linux/clk.h> 2761bfbdb8SLars-Peter Clausen 2861bfbdb8SLars-Peter Clausen #include <linux/bitops.h> 2961bfbdb8SLars-Peter Clausen #include <linux/gpio.h> 3061bfbdb8SLars-Peter Clausen #include <asm/mach-jz4740/gpio.h> 3161bfbdb8SLars-Peter Clausen #include <asm/cacheflush.h> 3261bfbdb8SLars-Peter Clausen #include <linux/dma-mapping.h> 337ca27a6fSApelete Seketeli #include <linux/dmaengine.h> 3461bfbdb8SLars-Peter Clausen 357ca27a6fSApelete Seketeli #include <asm/mach-jz4740/dma.h> 3661bfbdb8SLars-Peter Clausen #include <asm/mach-jz4740/jz4740_mmc.h> 3761bfbdb8SLars-Peter Clausen 3861bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_STRPCL 0x00 3961bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_STATUS 0x04 4061bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_CLKRT 0x08 4161bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_CMDAT 0x0C 4261bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RESTO 0x10 4361bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RDTO 0x14 4461bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_BLKLEN 0x18 4561bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_NOB 0x1C 4661bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_SNOB 0x20 4761bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_IMASK 0x24 4861bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_IREG 0x28 4961bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_CMD 0x2C 5061bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_ARG 0x30 5161bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RESP_FIFO 0x34 5261bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RXFIFO 0x38 5361bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_TXFIFO 0x3C 5461bfbdb8SLars-Peter Clausen 5561bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) 5661bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6) 5761bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_START_READWAIT BIT(5) 5861bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_STOP_READWAIT BIT(4) 5961bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_RESET BIT(3) 6061bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_START_OP BIT(2) 6161bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0)) 6261bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_CLOCK_STOP BIT(0) 6361bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_CLOCK_START BIT(1) 6461bfbdb8SLars-Peter Clausen 6561bfbdb8SLars-Peter Clausen 6661bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_IS_RESETTING BIT(15) 6761bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14) 6861bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_PRG_DONE BIT(13) 6961bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12) 7061bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_END_CMD_RES BIT(11) 7161bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10) 7261bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_IS_READWAIT BIT(9) 7361bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CLK_EN BIT(8) 7461bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7) 7561bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6) 7661bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CRC_RES_ERR BIT(5) 7761bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4) 7861bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3) 7961bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2) 8061bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_TIMEOUT_RES BIT(1) 8161bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_TIMEOUT_READ BIT(0) 8261bfbdb8SLars-Peter Clausen 8361bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0)) 8461bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2)) 8561bfbdb8SLars-Peter Clausen 8661bfbdb8SLars-Peter Clausen 8761bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_IO_ABORT BIT(11) 8861bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10) 8961bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_DMA_EN BIT(8) 9061bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_INIT BIT(7) 9161bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_BUSY BIT(6) 9261bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_STREAM BIT(5) 9361bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_WRITE BIT(4) 9461bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_DATA_EN BIT(3) 9561bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0)) 9661bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RSP_R1 1 9761bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RSP_R2 2 9861bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RSP_R3 3 9961bfbdb8SLars-Peter Clausen 10061bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_SDIO BIT(7) 10161bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6) 10261bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5) 10361bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_END_CMD_RES BIT(2) 10461bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_PRG_DONE BIT(1) 10561bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0) 10661bfbdb8SLars-Peter Clausen 10761bfbdb8SLars-Peter Clausen 10861bfbdb8SLars-Peter Clausen #define JZ_MMC_CLK_RATE 24000000 10961bfbdb8SLars-Peter Clausen 11061bfbdb8SLars-Peter Clausen enum jz4740_mmc_state { 11161bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_READ_RESPONSE, 11261bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_TRANSFER_DATA, 11361bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_SEND_STOP, 11461bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_DONE, 11561bfbdb8SLars-Peter Clausen }; 11661bfbdb8SLars-Peter Clausen 11761bfbdb8SLars-Peter Clausen struct jz4740_mmc_host { 11861bfbdb8SLars-Peter Clausen struct mmc_host *mmc; 11961bfbdb8SLars-Peter Clausen struct platform_device *pdev; 12061bfbdb8SLars-Peter Clausen struct jz4740_mmc_platform_data *pdata; 12161bfbdb8SLars-Peter Clausen struct clk *clk; 12261bfbdb8SLars-Peter Clausen 12361bfbdb8SLars-Peter Clausen int irq; 12461bfbdb8SLars-Peter Clausen int card_detect_irq; 12561bfbdb8SLars-Peter Clausen 12661bfbdb8SLars-Peter Clausen void __iomem *base; 1277ca27a6fSApelete Seketeli struct resource *mem_res; 12861bfbdb8SLars-Peter Clausen struct mmc_request *req; 12961bfbdb8SLars-Peter Clausen struct mmc_command *cmd; 13061bfbdb8SLars-Peter Clausen 13161bfbdb8SLars-Peter Clausen unsigned long waiting; 13261bfbdb8SLars-Peter Clausen 13361bfbdb8SLars-Peter Clausen uint32_t cmdat; 13461bfbdb8SLars-Peter Clausen 13561bfbdb8SLars-Peter Clausen uint16_t irq_mask; 13661bfbdb8SLars-Peter Clausen 13761bfbdb8SLars-Peter Clausen spinlock_t lock; 13861bfbdb8SLars-Peter Clausen 13961bfbdb8SLars-Peter Clausen struct timer_list timeout_timer; 14061bfbdb8SLars-Peter Clausen struct sg_mapping_iter miter; 14161bfbdb8SLars-Peter Clausen enum jz4740_mmc_state state; 1427ca27a6fSApelete Seketeli 1437ca27a6fSApelete Seketeli /* DMA support */ 1447ca27a6fSApelete Seketeli struct dma_chan *dma_rx; 1457ca27a6fSApelete Seketeli struct dma_chan *dma_tx; 1467ca27a6fSApelete Seketeli bool use_dma; 1477ca27a6fSApelete Seketeli int sg_len; 1487ca27a6fSApelete Seketeli 1497ca27a6fSApelete Seketeli /* The DMA trigger level is 8 words, that is to say, the DMA read 1507ca27a6fSApelete Seketeli * trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write 1517ca27a6fSApelete Seketeli * trigger is when data words in MSC_TXFIFO is < 8. 1527ca27a6fSApelete Seketeli */ 1537ca27a6fSApelete Seketeli #define JZ4740_MMC_FIFO_HALF_SIZE 8 15461bfbdb8SLars-Peter Clausen }; 15561bfbdb8SLars-Peter Clausen 1567ca27a6fSApelete Seketeli /*----------------------------------------------------------------------------*/ 1577ca27a6fSApelete Seketeli /* DMA infrastructure */ 1587ca27a6fSApelete Seketeli 1597ca27a6fSApelete Seketeli static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host) 1607ca27a6fSApelete Seketeli { 1617ca27a6fSApelete Seketeli if (!host->use_dma) 1627ca27a6fSApelete Seketeli return; 1637ca27a6fSApelete Seketeli 1647ca27a6fSApelete Seketeli dma_release_channel(host->dma_tx); 1657ca27a6fSApelete Seketeli dma_release_channel(host->dma_rx); 1667ca27a6fSApelete Seketeli } 1677ca27a6fSApelete Seketeli 1687ca27a6fSApelete Seketeli static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) 1697ca27a6fSApelete Seketeli { 1707ca27a6fSApelete Seketeli dma_cap_mask_t mask; 1717ca27a6fSApelete Seketeli 1727ca27a6fSApelete Seketeli dma_cap_zero(mask); 1737ca27a6fSApelete Seketeli dma_cap_set(DMA_SLAVE, mask); 1747ca27a6fSApelete Seketeli 1757ca27a6fSApelete Seketeli host->dma_tx = dma_request_channel(mask, NULL, host); 1767ca27a6fSApelete Seketeli if (!host->dma_tx) { 1777ca27a6fSApelete Seketeli dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n"); 1787ca27a6fSApelete Seketeli return -ENODEV; 1797ca27a6fSApelete Seketeli } 1807ca27a6fSApelete Seketeli 1817ca27a6fSApelete Seketeli host->dma_rx = dma_request_channel(mask, NULL, host); 1827ca27a6fSApelete Seketeli if (!host->dma_rx) { 1837ca27a6fSApelete Seketeli dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n"); 1847ca27a6fSApelete Seketeli goto free_master_write; 1857ca27a6fSApelete Seketeli } 1867ca27a6fSApelete Seketeli 1877ca27a6fSApelete Seketeli return 0; 1887ca27a6fSApelete Seketeli 1897ca27a6fSApelete Seketeli free_master_write: 1907ca27a6fSApelete Seketeli dma_release_channel(host->dma_tx); 1917ca27a6fSApelete Seketeli return -ENODEV; 1927ca27a6fSApelete Seketeli } 1937ca27a6fSApelete Seketeli 1947ca27a6fSApelete Seketeli static inline int jz4740_mmc_get_dma_dir(struct mmc_data *data) 1957ca27a6fSApelete Seketeli { 1967ca27a6fSApelete Seketeli return (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 1977ca27a6fSApelete Seketeli } 1987ca27a6fSApelete Seketeli 1997ca27a6fSApelete Seketeli static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host, 2007ca27a6fSApelete Seketeli struct mmc_data *data) 2017ca27a6fSApelete Seketeli { 2027ca27a6fSApelete Seketeli struct dma_chan *chan; 2037ca27a6fSApelete Seketeli enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data); 2047ca27a6fSApelete Seketeli 2057ca27a6fSApelete Seketeli if (dir == DMA_TO_DEVICE) 2067ca27a6fSApelete Seketeli chan = host->dma_tx; 2077ca27a6fSApelete Seketeli else 2087ca27a6fSApelete Seketeli chan = host->dma_rx; 2097ca27a6fSApelete Seketeli 2107ca27a6fSApelete Seketeli dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); 2117ca27a6fSApelete Seketeli } 2127ca27a6fSApelete Seketeli 2137ca27a6fSApelete Seketeli static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host, 2147ca27a6fSApelete Seketeli struct mmc_data *data) 2157ca27a6fSApelete Seketeli { 2167ca27a6fSApelete Seketeli struct dma_chan *chan; 2177ca27a6fSApelete Seketeli struct dma_async_tx_descriptor *desc; 2187ca27a6fSApelete Seketeli struct dma_slave_config conf = { 2197ca27a6fSApelete Seketeli .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 2207ca27a6fSApelete Seketeli .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 2217ca27a6fSApelete Seketeli .src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE, 2227ca27a6fSApelete Seketeli .dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE, 2237ca27a6fSApelete Seketeli }; 2247ca27a6fSApelete Seketeli enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data); 2257ca27a6fSApelete Seketeli 2267ca27a6fSApelete Seketeli if (dir == DMA_TO_DEVICE) { 2277ca27a6fSApelete Seketeli conf.direction = DMA_MEM_TO_DEV; 2287ca27a6fSApelete Seketeli conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO; 2297ca27a6fSApelete Seketeli conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT; 2307ca27a6fSApelete Seketeli chan = host->dma_tx; 2317ca27a6fSApelete Seketeli } else { 2327ca27a6fSApelete Seketeli conf.direction = DMA_DEV_TO_MEM; 2337ca27a6fSApelete Seketeli conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO; 2347ca27a6fSApelete Seketeli conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE; 2357ca27a6fSApelete Seketeli chan = host->dma_rx; 2367ca27a6fSApelete Seketeli } 2377ca27a6fSApelete Seketeli 2387ca27a6fSApelete Seketeli host->sg_len = dma_map_sg(chan->device->dev, 2397ca27a6fSApelete Seketeli data->sg, 2407ca27a6fSApelete Seketeli data->sg_len, 2417ca27a6fSApelete Seketeli dir); 2427ca27a6fSApelete Seketeli 2437ca27a6fSApelete Seketeli if (host->sg_len == 0) { 2447ca27a6fSApelete Seketeli dev_err(mmc_dev(host->mmc), 2457ca27a6fSApelete Seketeli "Failed to map scatterlist for DMA operation\n"); 2467ca27a6fSApelete Seketeli return -EINVAL; 2477ca27a6fSApelete Seketeli } 2487ca27a6fSApelete Seketeli 2497ca27a6fSApelete Seketeli dmaengine_slave_config(chan, &conf); 2507ca27a6fSApelete Seketeli desc = dmaengine_prep_slave_sg(chan, 2517ca27a6fSApelete Seketeli data->sg, 2527ca27a6fSApelete Seketeli host->sg_len, 2537ca27a6fSApelete Seketeli conf.direction, 2547ca27a6fSApelete Seketeli DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 2557ca27a6fSApelete Seketeli if (!desc) { 2567ca27a6fSApelete Seketeli dev_err(mmc_dev(host->mmc), 2577ca27a6fSApelete Seketeli "Failed to allocate DMA %s descriptor", 2587ca27a6fSApelete Seketeli conf.direction == DMA_MEM_TO_DEV ? "TX" : "RX"); 2597ca27a6fSApelete Seketeli goto dma_unmap; 2607ca27a6fSApelete Seketeli } 2617ca27a6fSApelete Seketeli 2627ca27a6fSApelete Seketeli dmaengine_submit(desc); 2637ca27a6fSApelete Seketeli dma_async_issue_pending(chan); 2647ca27a6fSApelete Seketeli 2657ca27a6fSApelete Seketeli return 0; 2667ca27a6fSApelete Seketeli 2677ca27a6fSApelete Seketeli dma_unmap: 2687ca27a6fSApelete Seketeli jz4740_mmc_dma_unmap(host, data); 2697ca27a6fSApelete Seketeli return -ENOMEM; 2707ca27a6fSApelete Seketeli } 2717ca27a6fSApelete Seketeli 2727ca27a6fSApelete Seketeli /*----------------------------------------------------------------------------*/ 2737ca27a6fSApelete Seketeli 27461bfbdb8SLars-Peter Clausen static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, 27561bfbdb8SLars-Peter Clausen unsigned int irq, bool enabled) 27661bfbdb8SLars-Peter Clausen { 27761bfbdb8SLars-Peter Clausen unsigned long flags; 27861bfbdb8SLars-Peter Clausen 27961bfbdb8SLars-Peter Clausen spin_lock_irqsave(&host->lock, flags); 28061bfbdb8SLars-Peter Clausen if (enabled) 28161bfbdb8SLars-Peter Clausen host->irq_mask &= ~irq; 28261bfbdb8SLars-Peter Clausen else 28361bfbdb8SLars-Peter Clausen host->irq_mask |= irq; 28461bfbdb8SLars-Peter Clausen spin_unlock_irqrestore(&host->lock, flags); 28561bfbdb8SLars-Peter Clausen 28661bfbdb8SLars-Peter Clausen writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); 28761bfbdb8SLars-Peter Clausen } 28861bfbdb8SLars-Peter Clausen 28961bfbdb8SLars-Peter Clausen static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, 29061bfbdb8SLars-Peter Clausen bool start_transfer) 29161bfbdb8SLars-Peter Clausen { 29261bfbdb8SLars-Peter Clausen uint16_t val = JZ_MMC_STRPCL_CLOCK_START; 29361bfbdb8SLars-Peter Clausen 29461bfbdb8SLars-Peter Clausen if (start_transfer) 29561bfbdb8SLars-Peter Clausen val |= JZ_MMC_STRPCL_START_OP; 29661bfbdb8SLars-Peter Clausen 29761bfbdb8SLars-Peter Clausen writew(val, host->base + JZ_REG_MMC_STRPCL); 29861bfbdb8SLars-Peter Clausen } 29961bfbdb8SLars-Peter Clausen 30061bfbdb8SLars-Peter Clausen static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host) 30161bfbdb8SLars-Peter Clausen { 30261bfbdb8SLars-Peter Clausen uint32_t status; 30361bfbdb8SLars-Peter Clausen unsigned int timeout = 1000; 30461bfbdb8SLars-Peter Clausen 30561bfbdb8SLars-Peter Clausen writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL); 30661bfbdb8SLars-Peter Clausen do { 30761bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 30861bfbdb8SLars-Peter Clausen } while (status & JZ_MMC_STATUS_CLK_EN && --timeout); 30961bfbdb8SLars-Peter Clausen } 31061bfbdb8SLars-Peter Clausen 31161bfbdb8SLars-Peter Clausen static void jz4740_mmc_reset(struct jz4740_mmc_host *host) 31261bfbdb8SLars-Peter Clausen { 31361bfbdb8SLars-Peter Clausen uint32_t status; 31461bfbdb8SLars-Peter Clausen unsigned int timeout = 1000; 31561bfbdb8SLars-Peter Clausen 31661bfbdb8SLars-Peter Clausen writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL); 31761bfbdb8SLars-Peter Clausen udelay(10); 31861bfbdb8SLars-Peter Clausen do { 31961bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 32061bfbdb8SLars-Peter Clausen } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout); 32161bfbdb8SLars-Peter Clausen } 32261bfbdb8SLars-Peter Clausen 32361bfbdb8SLars-Peter Clausen static void jz4740_mmc_request_done(struct jz4740_mmc_host *host) 32461bfbdb8SLars-Peter Clausen { 32561bfbdb8SLars-Peter Clausen struct mmc_request *req; 32661bfbdb8SLars-Peter Clausen 32761bfbdb8SLars-Peter Clausen req = host->req; 32861bfbdb8SLars-Peter Clausen host->req = NULL; 32961bfbdb8SLars-Peter Clausen 33061bfbdb8SLars-Peter Clausen mmc_request_done(host->mmc, req); 33161bfbdb8SLars-Peter Clausen } 33261bfbdb8SLars-Peter Clausen 33361bfbdb8SLars-Peter Clausen static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, 33461bfbdb8SLars-Peter Clausen unsigned int irq) 33561bfbdb8SLars-Peter Clausen { 33661bfbdb8SLars-Peter Clausen unsigned int timeout = 0x800; 33761bfbdb8SLars-Peter Clausen uint16_t status; 33861bfbdb8SLars-Peter Clausen 33961bfbdb8SLars-Peter Clausen do { 34061bfbdb8SLars-Peter Clausen status = readw(host->base + JZ_REG_MMC_IREG); 34161bfbdb8SLars-Peter Clausen } while (!(status & irq) && --timeout); 34261bfbdb8SLars-Peter Clausen 34361bfbdb8SLars-Peter Clausen if (timeout == 0) { 34461bfbdb8SLars-Peter Clausen set_bit(0, &host->waiting); 34561bfbdb8SLars-Peter Clausen mod_timer(&host->timeout_timer, jiffies + 5*HZ); 34661bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, irq, true); 34761bfbdb8SLars-Peter Clausen return true; 34861bfbdb8SLars-Peter Clausen } 34961bfbdb8SLars-Peter Clausen 35061bfbdb8SLars-Peter Clausen return false; 35161bfbdb8SLars-Peter Clausen } 35261bfbdb8SLars-Peter Clausen 35361bfbdb8SLars-Peter Clausen static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host, 35461bfbdb8SLars-Peter Clausen struct mmc_data *data) 35561bfbdb8SLars-Peter Clausen { 35661bfbdb8SLars-Peter Clausen int status; 35761bfbdb8SLars-Peter Clausen 35861bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 35961bfbdb8SLars-Peter Clausen if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) { 36061bfbdb8SLars-Peter Clausen if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) { 36161bfbdb8SLars-Peter Clausen host->req->cmd->error = -ETIMEDOUT; 36261bfbdb8SLars-Peter Clausen data->error = -ETIMEDOUT; 36361bfbdb8SLars-Peter Clausen } else { 36461bfbdb8SLars-Peter Clausen host->req->cmd->error = -EIO; 36561bfbdb8SLars-Peter Clausen data->error = -EIO; 36661bfbdb8SLars-Peter Clausen } 3678a489aa1SPaul Cercueil } else if (status & JZ_MMC_STATUS_READ_ERROR_MASK) { 3688a489aa1SPaul Cercueil if (status & (JZ_MMC_STATUS_TIMEOUT_READ)) { 3698a489aa1SPaul Cercueil host->req->cmd->error = -ETIMEDOUT; 3708a489aa1SPaul Cercueil data->error = -ETIMEDOUT; 3718a489aa1SPaul Cercueil } else { 3728a489aa1SPaul Cercueil host->req->cmd->error = -EIO; 3738a489aa1SPaul Cercueil data->error = -EIO; 3748a489aa1SPaul Cercueil } 37561bfbdb8SLars-Peter Clausen } 37661bfbdb8SLars-Peter Clausen } 37761bfbdb8SLars-Peter Clausen 37861bfbdb8SLars-Peter Clausen static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host, 37961bfbdb8SLars-Peter Clausen struct mmc_data *data) 38061bfbdb8SLars-Peter Clausen { 38161bfbdb8SLars-Peter Clausen struct sg_mapping_iter *miter = &host->miter; 38261bfbdb8SLars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO; 38361bfbdb8SLars-Peter Clausen uint32_t *buf; 38461bfbdb8SLars-Peter Clausen bool timeout; 38561bfbdb8SLars-Peter Clausen size_t i, j; 38661bfbdb8SLars-Peter Clausen 38761bfbdb8SLars-Peter Clausen while (sg_miter_next(miter)) { 38861bfbdb8SLars-Peter Clausen buf = miter->addr; 38961bfbdb8SLars-Peter Clausen i = miter->length / 4; 39061bfbdb8SLars-Peter Clausen j = i / 8; 39161bfbdb8SLars-Peter Clausen i = i & 0x7; 39261bfbdb8SLars-Peter Clausen while (j) { 39361bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); 39461bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 39561bfbdb8SLars-Peter Clausen goto poll_timeout; 39661bfbdb8SLars-Peter Clausen 39761bfbdb8SLars-Peter Clausen writel(buf[0], fifo_addr); 39861bfbdb8SLars-Peter Clausen writel(buf[1], fifo_addr); 39961bfbdb8SLars-Peter Clausen writel(buf[2], fifo_addr); 40061bfbdb8SLars-Peter Clausen writel(buf[3], fifo_addr); 40161bfbdb8SLars-Peter Clausen writel(buf[4], fifo_addr); 40261bfbdb8SLars-Peter Clausen writel(buf[5], fifo_addr); 40361bfbdb8SLars-Peter Clausen writel(buf[6], fifo_addr); 40461bfbdb8SLars-Peter Clausen writel(buf[7], fifo_addr); 40561bfbdb8SLars-Peter Clausen buf += 8; 40661bfbdb8SLars-Peter Clausen --j; 40761bfbdb8SLars-Peter Clausen } 40861bfbdb8SLars-Peter Clausen if (unlikely(i)) { 40961bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); 41061bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 41161bfbdb8SLars-Peter Clausen goto poll_timeout; 41261bfbdb8SLars-Peter Clausen 41361bfbdb8SLars-Peter Clausen while (i) { 41461bfbdb8SLars-Peter Clausen writel(*buf, fifo_addr); 41561bfbdb8SLars-Peter Clausen ++buf; 41661bfbdb8SLars-Peter Clausen --i; 41761bfbdb8SLars-Peter Clausen } 41861bfbdb8SLars-Peter Clausen } 41961bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->length; 42061bfbdb8SLars-Peter Clausen } 42161bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 42261bfbdb8SLars-Peter Clausen 42361bfbdb8SLars-Peter Clausen return false; 42461bfbdb8SLars-Peter Clausen 42561bfbdb8SLars-Peter Clausen poll_timeout: 42661bfbdb8SLars-Peter Clausen miter->consumed = (void *)buf - miter->addr; 42761bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->consumed; 42861bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 42961bfbdb8SLars-Peter Clausen 43061bfbdb8SLars-Peter Clausen return true; 43161bfbdb8SLars-Peter Clausen } 43261bfbdb8SLars-Peter Clausen 43361bfbdb8SLars-Peter Clausen static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, 43461bfbdb8SLars-Peter Clausen struct mmc_data *data) 43561bfbdb8SLars-Peter Clausen { 43661bfbdb8SLars-Peter Clausen struct sg_mapping_iter *miter = &host->miter; 43761bfbdb8SLars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO; 43861bfbdb8SLars-Peter Clausen uint32_t *buf; 43961bfbdb8SLars-Peter Clausen uint32_t d; 44061bfbdb8SLars-Peter Clausen uint16_t status; 44161bfbdb8SLars-Peter Clausen size_t i, j; 44261bfbdb8SLars-Peter Clausen unsigned int timeout; 44361bfbdb8SLars-Peter Clausen 44461bfbdb8SLars-Peter Clausen while (sg_miter_next(miter)) { 44561bfbdb8SLars-Peter Clausen buf = miter->addr; 44661bfbdb8SLars-Peter Clausen i = miter->length; 44761bfbdb8SLars-Peter Clausen j = i / 32; 44861bfbdb8SLars-Peter Clausen i = i & 0x1f; 44961bfbdb8SLars-Peter Clausen while (j) { 45061bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); 45161bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 45261bfbdb8SLars-Peter Clausen goto poll_timeout; 45361bfbdb8SLars-Peter Clausen 45461bfbdb8SLars-Peter Clausen buf[0] = readl(fifo_addr); 45561bfbdb8SLars-Peter Clausen buf[1] = readl(fifo_addr); 45661bfbdb8SLars-Peter Clausen buf[2] = readl(fifo_addr); 45761bfbdb8SLars-Peter Clausen buf[3] = readl(fifo_addr); 45861bfbdb8SLars-Peter Clausen buf[4] = readl(fifo_addr); 45961bfbdb8SLars-Peter Clausen buf[5] = readl(fifo_addr); 46061bfbdb8SLars-Peter Clausen buf[6] = readl(fifo_addr); 46161bfbdb8SLars-Peter Clausen buf[7] = readl(fifo_addr); 46261bfbdb8SLars-Peter Clausen 46361bfbdb8SLars-Peter Clausen buf += 8; 46461bfbdb8SLars-Peter Clausen --j; 46561bfbdb8SLars-Peter Clausen } 46661bfbdb8SLars-Peter Clausen 46761bfbdb8SLars-Peter Clausen if (unlikely(i)) { 46861bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); 46961bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 47061bfbdb8SLars-Peter Clausen goto poll_timeout; 47161bfbdb8SLars-Peter Clausen 47261bfbdb8SLars-Peter Clausen while (i >= 4) { 47361bfbdb8SLars-Peter Clausen *buf++ = readl(fifo_addr); 47461bfbdb8SLars-Peter Clausen i -= 4; 47561bfbdb8SLars-Peter Clausen } 47661bfbdb8SLars-Peter Clausen if (unlikely(i > 0)) { 47761bfbdb8SLars-Peter Clausen d = readl(fifo_addr); 47861bfbdb8SLars-Peter Clausen memcpy(buf, &d, i); 47961bfbdb8SLars-Peter Clausen } 48061bfbdb8SLars-Peter Clausen } 48161bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->length; 48261bfbdb8SLars-Peter Clausen 48361bfbdb8SLars-Peter Clausen /* This can go away once MIPS implements 48461bfbdb8SLars-Peter Clausen * flush_kernel_dcache_page */ 48561bfbdb8SLars-Peter Clausen flush_dcache_page(miter->page); 48661bfbdb8SLars-Peter Clausen } 48761bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 48861bfbdb8SLars-Peter Clausen 48961bfbdb8SLars-Peter Clausen /* For whatever reason there is sometime one word more in the fifo then 49061bfbdb8SLars-Peter Clausen * requested */ 49161bfbdb8SLars-Peter Clausen timeout = 1000; 49261bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 49361bfbdb8SLars-Peter Clausen while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) { 49461bfbdb8SLars-Peter Clausen d = readl(fifo_addr); 49561bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 49661bfbdb8SLars-Peter Clausen } 49761bfbdb8SLars-Peter Clausen 49861bfbdb8SLars-Peter Clausen return false; 49961bfbdb8SLars-Peter Clausen 50061bfbdb8SLars-Peter Clausen poll_timeout: 50161bfbdb8SLars-Peter Clausen miter->consumed = (void *)buf - miter->addr; 50261bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->consumed; 50361bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 50461bfbdb8SLars-Peter Clausen 50561bfbdb8SLars-Peter Clausen return true; 50661bfbdb8SLars-Peter Clausen } 50761bfbdb8SLars-Peter Clausen 50861bfbdb8SLars-Peter Clausen static void jz4740_mmc_timeout(unsigned long data) 50961bfbdb8SLars-Peter Clausen { 51061bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data; 51161bfbdb8SLars-Peter Clausen 51261bfbdb8SLars-Peter Clausen if (!test_and_clear_bit(0, &host->waiting)) 51361bfbdb8SLars-Peter Clausen return; 51461bfbdb8SLars-Peter Clausen 51561bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false); 51661bfbdb8SLars-Peter Clausen 51761bfbdb8SLars-Peter Clausen host->req->cmd->error = -ETIMEDOUT; 51861bfbdb8SLars-Peter Clausen jz4740_mmc_request_done(host); 51961bfbdb8SLars-Peter Clausen } 52061bfbdb8SLars-Peter Clausen 52161bfbdb8SLars-Peter Clausen static void jz4740_mmc_read_response(struct jz4740_mmc_host *host, 52261bfbdb8SLars-Peter Clausen struct mmc_command *cmd) 52361bfbdb8SLars-Peter Clausen { 52461bfbdb8SLars-Peter Clausen int i; 52561bfbdb8SLars-Peter Clausen uint16_t tmp; 52661bfbdb8SLars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO; 52761bfbdb8SLars-Peter Clausen 52861bfbdb8SLars-Peter Clausen if (cmd->flags & MMC_RSP_136) { 52961bfbdb8SLars-Peter Clausen tmp = readw(fifo_addr); 53061bfbdb8SLars-Peter Clausen for (i = 0; i < 4; ++i) { 53161bfbdb8SLars-Peter Clausen cmd->resp[i] = tmp << 24; 53261bfbdb8SLars-Peter Clausen tmp = readw(fifo_addr); 53361bfbdb8SLars-Peter Clausen cmd->resp[i] |= tmp << 8; 53461bfbdb8SLars-Peter Clausen tmp = readw(fifo_addr); 53561bfbdb8SLars-Peter Clausen cmd->resp[i] |= tmp >> 8; 53661bfbdb8SLars-Peter Clausen } 53761bfbdb8SLars-Peter Clausen } else { 53861bfbdb8SLars-Peter Clausen cmd->resp[0] = readw(fifo_addr) << 24; 53961bfbdb8SLars-Peter Clausen cmd->resp[0] |= readw(fifo_addr) << 8; 54061bfbdb8SLars-Peter Clausen cmd->resp[0] |= readw(fifo_addr) & 0xff; 54161bfbdb8SLars-Peter Clausen } 54261bfbdb8SLars-Peter Clausen } 54361bfbdb8SLars-Peter Clausen 54461bfbdb8SLars-Peter Clausen static void jz4740_mmc_send_command(struct jz4740_mmc_host *host, 54561bfbdb8SLars-Peter Clausen struct mmc_command *cmd) 54661bfbdb8SLars-Peter Clausen { 54761bfbdb8SLars-Peter Clausen uint32_t cmdat = host->cmdat; 54861bfbdb8SLars-Peter Clausen 54961bfbdb8SLars-Peter Clausen host->cmdat &= ~JZ_MMC_CMDAT_INIT; 55061bfbdb8SLars-Peter Clausen jz4740_mmc_clock_disable(host); 55161bfbdb8SLars-Peter Clausen 55261bfbdb8SLars-Peter Clausen host->cmd = cmd; 55361bfbdb8SLars-Peter Clausen 55461bfbdb8SLars-Peter Clausen if (cmd->flags & MMC_RSP_BUSY) 55561bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_BUSY; 55661bfbdb8SLars-Peter Clausen 55761bfbdb8SLars-Peter Clausen switch (mmc_resp_type(cmd)) { 55861bfbdb8SLars-Peter Clausen case MMC_RSP_R1B: 55961bfbdb8SLars-Peter Clausen case MMC_RSP_R1: 56061bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R1; 56161bfbdb8SLars-Peter Clausen break; 56261bfbdb8SLars-Peter Clausen case MMC_RSP_R2: 56361bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R2; 56461bfbdb8SLars-Peter Clausen break; 56561bfbdb8SLars-Peter Clausen case MMC_RSP_R3: 56661bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R3; 56761bfbdb8SLars-Peter Clausen break; 56861bfbdb8SLars-Peter Clausen default: 56961bfbdb8SLars-Peter Clausen break; 57061bfbdb8SLars-Peter Clausen } 57161bfbdb8SLars-Peter Clausen 57261bfbdb8SLars-Peter Clausen if (cmd->data) { 57361bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_DATA_EN; 57461bfbdb8SLars-Peter Clausen if (cmd->data->flags & MMC_DATA_WRITE) 57561bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_WRITE; 57661bfbdb8SLars-Peter Clausen if (cmd->data->flags & MMC_DATA_STREAM) 57761bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_STREAM; 5787ca27a6fSApelete Seketeli if (host->use_dma) 5797ca27a6fSApelete Seketeli cmdat |= JZ_MMC_CMDAT_DMA_EN; 58061bfbdb8SLars-Peter Clausen 58161bfbdb8SLars-Peter Clausen writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN); 58261bfbdb8SLars-Peter Clausen writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB); 58361bfbdb8SLars-Peter Clausen } 58461bfbdb8SLars-Peter Clausen 58561bfbdb8SLars-Peter Clausen writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD); 58661bfbdb8SLars-Peter Clausen writel(cmd->arg, host->base + JZ_REG_MMC_ARG); 58761bfbdb8SLars-Peter Clausen writel(cmdat, host->base + JZ_REG_MMC_CMDAT); 58861bfbdb8SLars-Peter Clausen 58961bfbdb8SLars-Peter Clausen jz4740_mmc_clock_enable(host, 1); 59061bfbdb8SLars-Peter Clausen } 59161bfbdb8SLars-Peter Clausen 59261bfbdb8SLars-Peter Clausen static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host) 59361bfbdb8SLars-Peter Clausen { 59461bfbdb8SLars-Peter Clausen struct mmc_command *cmd = host->req->cmd; 59561bfbdb8SLars-Peter Clausen struct mmc_data *data = cmd->data; 59661bfbdb8SLars-Peter Clausen int direction; 59761bfbdb8SLars-Peter Clausen 59861bfbdb8SLars-Peter Clausen if (data->flags & MMC_DATA_READ) 59961bfbdb8SLars-Peter Clausen direction = SG_MITER_TO_SG; 60061bfbdb8SLars-Peter Clausen else 60161bfbdb8SLars-Peter Clausen direction = SG_MITER_FROM_SG; 60261bfbdb8SLars-Peter Clausen 60361bfbdb8SLars-Peter Clausen sg_miter_start(&host->miter, data->sg, data->sg_len, direction); 60461bfbdb8SLars-Peter Clausen } 60561bfbdb8SLars-Peter Clausen 60661bfbdb8SLars-Peter Clausen 60761bfbdb8SLars-Peter Clausen static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) 60861bfbdb8SLars-Peter Clausen { 60961bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid; 61061bfbdb8SLars-Peter Clausen struct mmc_command *cmd = host->req->cmd; 61161bfbdb8SLars-Peter Clausen struct mmc_request *req = host->req; 6127ca27a6fSApelete Seketeli struct mmc_data *data = cmd->data; 61361bfbdb8SLars-Peter Clausen bool timeout = false; 61461bfbdb8SLars-Peter Clausen 61561bfbdb8SLars-Peter Clausen if (cmd->error) 61661bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_DONE; 61761bfbdb8SLars-Peter Clausen 61861bfbdb8SLars-Peter Clausen switch (host->state) { 61961bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_READ_RESPONSE: 62061bfbdb8SLars-Peter Clausen if (cmd->flags & MMC_RSP_PRESENT) 62161bfbdb8SLars-Peter Clausen jz4740_mmc_read_response(host, cmd); 62261bfbdb8SLars-Peter Clausen 6237ca27a6fSApelete Seketeli if (!data) 62461bfbdb8SLars-Peter Clausen break; 62561bfbdb8SLars-Peter Clausen 62661bfbdb8SLars-Peter Clausen jz_mmc_prepare_data_transfer(host); 62761bfbdb8SLars-Peter Clausen 62861bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_TRANSFER_DATA: 6297ca27a6fSApelete Seketeli if (host->use_dma) { 6307ca27a6fSApelete Seketeli /* Use DMA if enabled, data transfer direction was 6317ca27a6fSApelete Seketeli * defined before in jz_mmc_prepare_data_transfer(). 6327ca27a6fSApelete Seketeli */ 6337ca27a6fSApelete Seketeli timeout = jz4740_mmc_start_dma_transfer(host, data); 6347ca27a6fSApelete Seketeli data->bytes_xfered = data->blocks * data->blksz; 6357ca27a6fSApelete Seketeli } else if (data->flags & MMC_DATA_READ) 6367ca27a6fSApelete Seketeli /* If DMA is not enabled, rely on data flags 6377ca27a6fSApelete Seketeli * to establish data transfer direction. 6387ca27a6fSApelete Seketeli */ 6397ca27a6fSApelete Seketeli timeout = jz4740_mmc_read_data(host, data); 64061bfbdb8SLars-Peter Clausen else 6417ca27a6fSApelete Seketeli timeout = jz4740_mmc_write_data(host, data); 64261bfbdb8SLars-Peter Clausen 64361bfbdb8SLars-Peter Clausen if (unlikely(timeout)) { 64461bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_TRANSFER_DATA; 64561bfbdb8SLars-Peter Clausen break; 64661bfbdb8SLars-Peter Clausen } 64761bfbdb8SLars-Peter Clausen 6487ca27a6fSApelete Seketeli jz4740_mmc_transfer_check_state(host, data); 64961bfbdb8SLars-Peter Clausen 65061bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE); 65161bfbdb8SLars-Peter Clausen if (unlikely(timeout)) { 65261bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_SEND_STOP; 65361bfbdb8SLars-Peter Clausen break; 65461bfbdb8SLars-Peter Clausen } 65561bfbdb8SLars-Peter Clausen writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); 65661bfbdb8SLars-Peter Clausen 65761bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_SEND_STOP: 65861bfbdb8SLars-Peter Clausen if (!req->stop) 65961bfbdb8SLars-Peter Clausen break; 66061bfbdb8SLars-Peter Clausen 66161bfbdb8SLars-Peter Clausen jz4740_mmc_send_command(host, req->stop); 66261bfbdb8SLars-Peter Clausen 6631acee84bSAlex Smith if (mmc_resp_type(req->stop) & MMC_RSP_BUSY) { 6641acee84bSAlex Smith timeout = jz4740_mmc_poll_irq(host, 6651acee84bSAlex Smith JZ_MMC_IRQ_PRG_DONE); 66661bfbdb8SLars-Peter Clausen if (timeout) { 66761bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_DONE; 66861bfbdb8SLars-Peter Clausen break; 66961bfbdb8SLars-Peter Clausen } 6701acee84bSAlex Smith } 67161bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_DONE: 67261bfbdb8SLars-Peter Clausen break; 67361bfbdb8SLars-Peter Clausen } 67461bfbdb8SLars-Peter Clausen 67561bfbdb8SLars-Peter Clausen if (!timeout) 67661bfbdb8SLars-Peter Clausen jz4740_mmc_request_done(host); 67761bfbdb8SLars-Peter Clausen 67861bfbdb8SLars-Peter Clausen return IRQ_HANDLED; 67961bfbdb8SLars-Peter Clausen } 68061bfbdb8SLars-Peter Clausen 68161bfbdb8SLars-Peter Clausen static irqreturn_t jz_mmc_irq(int irq, void *devid) 68261bfbdb8SLars-Peter Clausen { 68361bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = devid; 68461bfbdb8SLars-Peter Clausen struct mmc_command *cmd = host->cmd; 68561bfbdb8SLars-Peter Clausen uint16_t irq_reg, status, tmp; 68661bfbdb8SLars-Peter Clausen 68761bfbdb8SLars-Peter Clausen irq_reg = readw(host->base + JZ_REG_MMC_IREG); 68861bfbdb8SLars-Peter Clausen 68961bfbdb8SLars-Peter Clausen tmp = irq_reg; 69061bfbdb8SLars-Peter Clausen irq_reg &= ~host->irq_mask; 69161bfbdb8SLars-Peter Clausen 69261bfbdb8SLars-Peter Clausen tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ | 69361bfbdb8SLars-Peter Clausen JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); 69461bfbdb8SLars-Peter Clausen 69561bfbdb8SLars-Peter Clausen if (tmp != irq_reg) 69661bfbdb8SLars-Peter Clausen writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); 69761bfbdb8SLars-Peter Clausen 69861bfbdb8SLars-Peter Clausen if (irq_reg & JZ_MMC_IRQ_SDIO) { 69961bfbdb8SLars-Peter Clausen writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG); 70061bfbdb8SLars-Peter Clausen mmc_signal_sdio_irq(host->mmc); 70161bfbdb8SLars-Peter Clausen irq_reg &= ~JZ_MMC_IRQ_SDIO; 70261bfbdb8SLars-Peter Clausen } 70361bfbdb8SLars-Peter Clausen 70461bfbdb8SLars-Peter Clausen if (host->req && cmd && irq_reg) { 70561bfbdb8SLars-Peter Clausen if (test_and_clear_bit(0, &host->waiting)) { 70661bfbdb8SLars-Peter Clausen del_timer(&host->timeout_timer); 70761bfbdb8SLars-Peter Clausen 70861bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 70961bfbdb8SLars-Peter Clausen 71061bfbdb8SLars-Peter Clausen if (status & JZ_MMC_STATUS_TIMEOUT_RES) { 71161bfbdb8SLars-Peter Clausen cmd->error = -ETIMEDOUT; 71261bfbdb8SLars-Peter Clausen } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { 71361bfbdb8SLars-Peter Clausen cmd->error = -EIO; 71461bfbdb8SLars-Peter Clausen } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | 71561bfbdb8SLars-Peter Clausen JZ_MMC_STATUS_CRC_WRITE_ERROR)) { 71661bfbdb8SLars-Peter Clausen if (cmd->data) 71761bfbdb8SLars-Peter Clausen cmd->data->error = -EIO; 71861bfbdb8SLars-Peter Clausen cmd->error = -EIO; 71961bfbdb8SLars-Peter Clausen } 72061bfbdb8SLars-Peter Clausen 72161bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, irq_reg, false); 72261bfbdb8SLars-Peter Clausen writew(irq_reg, host->base + JZ_REG_MMC_IREG); 72361bfbdb8SLars-Peter Clausen 72461bfbdb8SLars-Peter Clausen return IRQ_WAKE_THREAD; 72561bfbdb8SLars-Peter Clausen } 72661bfbdb8SLars-Peter Clausen } 72761bfbdb8SLars-Peter Clausen 72861bfbdb8SLars-Peter Clausen return IRQ_HANDLED; 72961bfbdb8SLars-Peter Clausen } 73061bfbdb8SLars-Peter Clausen 73161bfbdb8SLars-Peter Clausen static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) 73261bfbdb8SLars-Peter Clausen { 73361bfbdb8SLars-Peter Clausen int div = 0; 73461bfbdb8SLars-Peter Clausen int real_rate; 73561bfbdb8SLars-Peter Clausen 73661bfbdb8SLars-Peter Clausen jz4740_mmc_clock_disable(host); 73761bfbdb8SLars-Peter Clausen clk_set_rate(host->clk, JZ_MMC_CLK_RATE); 73861bfbdb8SLars-Peter Clausen 73961bfbdb8SLars-Peter Clausen real_rate = clk_get_rate(host->clk); 74061bfbdb8SLars-Peter Clausen 74161bfbdb8SLars-Peter Clausen while (real_rate > rate && div < 7) { 74261bfbdb8SLars-Peter Clausen ++div; 74361bfbdb8SLars-Peter Clausen real_rate >>= 1; 74461bfbdb8SLars-Peter Clausen } 74561bfbdb8SLars-Peter Clausen 74661bfbdb8SLars-Peter Clausen writew(div, host->base + JZ_REG_MMC_CLKRT); 74761bfbdb8SLars-Peter Clausen return real_rate; 74861bfbdb8SLars-Peter Clausen } 74961bfbdb8SLars-Peter Clausen 75061bfbdb8SLars-Peter Clausen static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) 75161bfbdb8SLars-Peter Clausen { 75261bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 75361bfbdb8SLars-Peter Clausen 75461bfbdb8SLars-Peter Clausen host->req = req; 75561bfbdb8SLars-Peter Clausen 75661bfbdb8SLars-Peter Clausen writew(0xffff, host->base + JZ_REG_MMC_IREG); 75761bfbdb8SLars-Peter Clausen 75861bfbdb8SLars-Peter Clausen writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); 75961bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true); 76061bfbdb8SLars-Peter Clausen 76161bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_READ_RESPONSE; 76261bfbdb8SLars-Peter Clausen set_bit(0, &host->waiting); 76361bfbdb8SLars-Peter Clausen mod_timer(&host->timeout_timer, jiffies + 5*HZ); 76461bfbdb8SLars-Peter Clausen jz4740_mmc_send_command(host, req->cmd); 76561bfbdb8SLars-Peter Clausen } 76661bfbdb8SLars-Peter Clausen 76761bfbdb8SLars-Peter Clausen static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 76861bfbdb8SLars-Peter Clausen { 76961bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 77061bfbdb8SLars-Peter Clausen if (ios->clock) 77161bfbdb8SLars-Peter Clausen jz4740_mmc_set_clock_rate(host, ios->clock); 77261bfbdb8SLars-Peter Clausen 77361bfbdb8SLars-Peter Clausen switch (ios->power_mode) { 77461bfbdb8SLars-Peter Clausen case MMC_POWER_UP: 77561bfbdb8SLars-Peter Clausen jz4740_mmc_reset(host); 77661bfbdb8SLars-Peter Clausen if (gpio_is_valid(host->pdata->gpio_power)) 77761bfbdb8SLars-Peter Clausen gpio_set_value(host->pdata->gpio_power, 77861bfbdb8SLars-Peter Clausen !host->pdata->power_active_low); 77961bfbdb8SLars-Peter Clausen host->cmdat |= JZ_MMC_CMDAT_INIT; 780fca9661cSLars-Peter Clausen clk_prepare_enable(host->clk); 78161bfbdb8SLars-Peter Clausen break; 78261bfbdb8SLars-Peter Clausen case MMC_POWER_ON: 78361bfbdb8SLars-Peter Clausen break; 78461bfbdb8SLars-Peter Clausen default: 78561bfbdb8SLars-Peter Clausen if (gpio_is_valid(host->pdata->gpio_power)) 78661bfbdb8SLars-Peter Clausen gpio_set_value(host->pdata->gpio_power, 78761bfbdb8SLars-Peter Clausen host->pdata->power_active_low); 788fca9661cSLars-Peter Clausen clk_disable_unprepare(host->clk); 78961bfbdb8SLars-Peter Clausen break; 79061bfbdb8SLars-Peter Clausen } 79161bfbdb8SLars-Peter Clausen 79261bfbdb8SLars-Peter Clausen switch (ios->bus_width) { 79361bfbdb8SLars-Peter Clausen case MMC_BUS_WIDTH_1: 79461bfbdb8SLars-Peter Clausen host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT; 79561bfbdb8SLars-Peter Clausen break; 79661bfbdb8SLars-Peter Clausen case MMC_BUS_WIDTH_4: 79761bfbdb8SLars-Peter Clausen host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT; 79861bfbdb8SLars-Peter Clausen break; 79961bfbdb8SLars-Peter Clausen default: 80061bfbdb8SLars-Peter Clausen break; 80161bfbdb8SLars-Peter Clausen } 80261bfbdb8SLars-Peter Clausen } 80361bfbdb8SLars-Peter Clausen 80461bfbdb8SLars-Peter Clausen static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) 80561bfbdb8SLars-Peter Clausen { 80661bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 80761bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable); 80861bfbdb8SLars-Peter Clausen } 80961bfbdb8SLars-Peter Clausen 81061bfbdb8SLars-Peter Clausen static const struct mmc_host_ops jz4740_mmc_ops = { 81161bfbdb8SLars-Peter Clausen .request = jz4740_mmc_request, 81261bfbdb8SLars-Peter Clausen .set_ios = jz4740_mmc_set_ios, 81358e300afSLars-Peter Clausen .get_ro = mmc_gpio_get_ro, 81458e300afSLars-Peter Clausen .get_cd = mmc_gpio_get_cd, 81561bfbdb8SLars-Peter Clausen .enable_sdio_irq = jz4740_mmc_enable_sdio_irq, 81661bfbdb8SLars-Peter Clausen }; 81761bfbdb8SLars-Peter Clausen 81861bfbdb8SLars-Peter Clausen static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = { 81961bfbdb8SLars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_CMD), 82061bfbdb8SLars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_CLK), 82161bfbdb8SLars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA0), 82261bfbdb8SLars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA1), 82361bfbdb8SLars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA2), 82461bfbdb8SLars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA3), 82561bfbdb8SLars-Peter Clausen }; 82661bfbdb8SLars-Peter Clausen 827c3be1efdSBill Pemberton static int jz4740_mmc_request_gpio(struct device *dev, int gpio, 82861bfbdb8SLars-Peter Clausen const char *name, bool output, int value) 82961bfbdb8SLars-Peter Clausen { 83061bfbdb8SLars-Peter Clausen int ret; 83161bfbdb8SLars-Peter Clausen 83261bfbdb8SLars-Peter Clausen if (!gpio_is_valid(gpio)) 83361bfbdb8SLars-Peter Clausen return 0; 83461bfbdb8SLars-Peter Clausen 83561bfbdb8SLars-Peter Clausen ret = gpio_request(gpio, name); 83661bfbdb8SLars-Peter Clausen if (ret) { 83761bfbdb8SLars-Peter Clausen dev_err(dev, "Failed to request %s gpio: %d\n", name, ret); 83861bfbdb8SLars-Peter Clausen return ret; 83961bfbdb8SLars-Peter Clausen } 84061bfbdb8SLars-Peter Clausen 84161bfbdb8SLars-Peter Clausen if (output) 84261bfbdb8SLars-Peter Clausen gpio_direction_output(gpio, value); 84361bfbdb8SLars-Peter Clausen else 84461bfbdb8SLars-Peter Clausen gpio_direction_input(gpio); 84561bfbdb8SLars-Peter Clausen 84661bfbdb8SLars-Peter Clausen return 0; 84761bfbdb8SLars-Peter Clausen } 84861bfbdb8SLars-Peter Clausen 84958e300afSLars-Peter Clausen static int jz4740_mmc_request_gpios(struct mmc_host *mmc, 85058e300afSLars-Peter Clausen struct platform_device *pdev) 85161bfbdb8SLars-Peter Clausen { 85261bfbdb8SLars-Peter Clausen struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; 85358e300afSLars-Peter Clausen int ret = 0; 85461bfbdb8SLars-Peter Clausen 85561bfbdb8SLars-Peter Clausen if (!pdata) 85661bfbdb8SLars-Peter Clausen return 0; 85761bfbdb8SLars-Peter Clausen 85858e300afSLars-Peter Clausen if (!pdata->card_detect_active_low) 85958e300afSLars-Peter Clausen mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; 86058e300afSLars-Peter Clausen if (!pdata->read_only_active_low) 86158e300afSLars-Peter Clausen mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; 86258e300afSLars-Peter Clausen 86358e300afSLars-Peter Clausen if (gpio_is_valid(pdata->gpio_card_detect)) { 864214fc309SLaurent Pinchart ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0); 86561bfbdb8SLars-Peter Clausen if (ret) 86661bfbdb8SLars-Peter Clausen return ret; 86761bfbdb8SLars-Peter Clausen } 86861bfbdb8SLars-Peter Clausen 86958e300afSLars-Peter Clausen if (gpio_is_valid(pdata->gpio_read_only)) { 87058e300afSLars-Peter Clausen ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only); 87158e300afSLars-Peter Clausen if (ret) 87258e300afSLars-Peter Clausen return ret; 87361bfbdb8SLars-Peter Clausen } 87461bfbdb8SLars-Peter Clausen 87558e300afSLars-Peter Clausen return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power, 87658e300afSLars-Peter Clausen "MMC read only", true, pdata->power_active_low); 87761bfbdb8SLars-Peter Clausen } 87861bfbdb8SLars-Peter Clausen 87961bfbdb8SLars-Peter Clausen static void jz4740_mmc_free_gpios(struct platform_device *pdev) 88061bfbdb8SLars-Peter Clausen { 88161bfbdb8SLars-Peter Clausen struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; 88261bfbdb8SLars-Peter Clausen 88361bfbdb8SLars-Peter Clausen if (!pdata) 88461bfbdb8SLars-Peter Clausen return; 88561bfbdb8SLars-Peter Clausen 88661bfbdb8SLars-Peter Clausen if (gpio_is_valid(pdata->gpio_power)) 88761bfbdb8SLars-Peter Clausen gpio_free(pdata->gpio_power); 88861bfbdb8SLars-Peter Clausen } 88961bfbdb8SLars-Peter Clausen 89061bfbdb8SLars-Peter Clausen static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host) 89161bfbdb8SLars-Peter Clausen { 89261bfbdb8SLars-Peter Clausen size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins); 89361bfbdb8SLars-Peter Clausen if (host->pdata && host->pdata->data_1bit) 89461bfbdb8SLars-Peter Clausen num_pins -= 3; 89561bfbdb8SLars-Peter Clausen 89661bfbdb8SLars-Peter Clausen return num_pins; 89761bfbdb8SLars-Peter Clausen } 89861bfbdb8SLars-Peter Clausen 899c3be1efdSBill Pemberton static int jz4740_mmc_probe(struct platform_device* pdev) 90061bfbdb8SLars-Peter Clausen { 90161bfbdb8SLars-Peter Clausen int ret; 90261bfbdb8SLars-Peter Clausen struct mmc_host *mmc; 90361bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host; 90461bfbdb8SLars-Peter Clausen struct jz4740_mmc_platform_data *pdata; 90561bfbdb8SLars-Peter Clausen 90661bfbdb8SLars-Peter Clausen pdata = pdev->dev.platform_data; 90761bfbdb8SLars-Peter Clausen 90861bfbdb8SLars-Peter Clausen mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); 90961bfbdb8SLars-Peter Clausen if (!mmc) { 91061bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to alloc mmc host structure\n"); 91161bfbdb8SLars-Peter Clausen return -ENOMEM; 91261bfbdb8SLars-Peter Clausen } 91361bfbdb8SLars-Peter Clausen 91461bfbdb8SLars-Peter Clausen host = mmc_priv(mmc); 91561bfbdb8SLars-Peter Clausen host->pdata = pdata; 91661bfbdb8SLars-Peter Clausen 91761bfbdb8SLars-Peter Clausen host->irq = platform_get_irq(pdev, 0); 91861bfbdb8SLars-Peter Clausen if (host->irq < 0) { 91961bfbdb8SLars-Peter Clausen ret = host->irq; 92061bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); 92161bfbdb8SLars-Peter Clausen goto err_free_host; 92261bfbdb8SLars-Peter Clausen } 92361bfbdb8SLars-Peter Clausen 924017d84bdSLars-Peter Clausen host->clk = devm_clk_get(&pdev->dev, "mmc"); 9253119cbdaSJamie Iles if (IS_ERR(host->clk)) { 9263119cbdaSJamie Iles ret = PTR_ERR(host->clk); 92761bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to get mmc clock\n"); 92861bfbdb8SLars-Peter Clausen goto err_free_host; 92961bfbdb8SLars-Peter Clausen } 93061bfbdb8SLars-Peter Clausen 9317ca27a6fSApelete Seketeli host->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9327ca27a6fSApelete Seketeli host->base = devm_ioremap_resource(&pdev->dev, host->mem_res); 9333e7e8c18SWei Yongjun if (IS_ERR(host->base)) { 9343e7e8c18SWei Yongjun ret = PTR_ERR(host->base); 9357ca27a6fSApelete Seketeli dev_err(&pdev->dev, "Failed to ioremap base memory\n"); 936017d84bdSLars-Peter Clausen goto err_free_host; 93761bfbdb8SLars-Peter Clausen } 93861bfbdb8SLars-Peter Clausen 93961bfbdb8SLars-Peter Clausen ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 94061bfbdb8SLars-Peter Clausen if (ret) { 94161bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret); 942017d84bdSLars-Peter Clausen goto err_free_host; 94361bfbdb8SLars-Peter Clausen } 94461bfbdb8SLars-Peter Clausen 94558e300afSLars-Peter Clausen ret = jz4740_mmc_request_gpios(mmc, pdev); 94661bfbdb8SLars-Peter Clausen if (ret) 94761bfbdb8SLars-Peter Clausen goto err_gpio_bulk_free; 94861bfbdb8SLars-Peter Clausen 94961bfbdb8SLars-Peter Clausen mmc->ops = &jz4740_mmc_ops; 95061bfbdb8SLars-Peter Clausen mmc->f_min = JZ_MMC_CLK_RATE / 128; 95161bfbdb8SLars-Peter Clausen mmc->f_max = JZ_MMC_CLK_RATE; 95261bfbdb8SLars-Peter Clausen mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 95361bfbdb8SLars-Peter Clausen mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA; 95461bfbdb8SLars-Peter Clausen mmc->caps |= MMC_CAP_SDIO_IRQ; 95561bfbdb8SLars-Peter Clausen 95661bfbdb8SLars-Peter Clausen mmc->max_blk_size = (1 << 10) - 1; 95761bfbdb8SLars-Peter Clausen mmc->max_blk_count = (1 << 15) - 1; 95861bfbdb8SLars-Peter Clausen mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 95961bfbdb8SLars-Peter Clausen 960a36274e0SMartin K. Petersen mmc->max_segs = 128; 96161bfbdb8SLars-Peter Clausen mmc->max_seg_size = mmc->max_req_size; 96261bfbdb8SLars-Peter Clausen 96361bfbdb8SLars-Peter Clausen host->mmc = mmc; 96461bfbdb8SLars-Peter Clausen host->pdev = pdev; 96561bfbdb8SLars-Peter Clausen spin_lock_init(&host->lock); 96661bfbdb8SLars-Peter Clausen host->irq_mask = 0xffff; 96761bfbdb8SLars-Peter Clausen 96861bfbdb8SLars-Peter Clausen ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, 96961bfbdb8SLars-Peter Clausen dev_name(&pdev->dev), host); 97061bfbdb8SLars-Peter Clausen if (ret) { 97161bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); 97258e300afSLars-Peter Clausen goto err_free_gpios; 97361bfbdb8SLars-Peter Clausen } 97461bfbdb8SLars-Peter Clausen 97561bfbdb8SLars-Peter Clausen jz4740_mmc_reset(host); 97661bfbdb8SLars-Peter Clausen jz4740_mmc_clock_disable(host); 97761bfbdb8SLars-Peter Clausen setup_timer(&host->timeout_timer, jz4740_mmc_timeout, 97861bfbdb8SLars-Peter Clausen (unsigned long)host); 97961bfbdb8SLars-Peter Clausen /* It is not important when it times out, it just needs to timeout. */ 98061bfbdb8SLars-Peter Clausen set_timer_slack(&host->timeout_timer, HZ); 98161bfbdb8SLars-Peter Clausen 9827ca27a6fSApelete Seketeli host->use_dma = true; 9837ca27a6fSApelete Seketeli if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0) 9847ca27a6fSApelete Seketeli host->use_dma = false; 9857ca27a6fSApelete Seketeli 98661bfbdb8SLars-Peter Clausen platform_set_drvdata(pdev, host); 98761bfbdb8SLars-Peter Clausen ret = mmc_add_host(mmc); 98861bfbdb8SLars-Peter Clausen 98961bfbdb8SLars-Peter Clausen if (ret) { 99061bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret); 99161bfbdb8SLars-Peter Clausen goto err_free_irq; 99261bfbdb8SLars-Peter Clausen } 99361bfbdb8SLars-Peter Clausen dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); 99461bfbdb8SLars-Peter Clausen 9957ca27a6fSApelete Seketeli dev_info(&pdev->dev, "Using %s, %d-bit mode\n", 9967ca27a6fSApelete Seketeli host->use_dma ? "DMA" : "PIO", 9977ca27a6fSApelete Seketeli (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1); 9987ca27a6fSApelete Seketeli 99961bfbdb8SLars-Peter Clausen return 0; 100061bfbdb8SLars-Peter Clausen 100161bfbdb8SLars-Peter Clausen err_free_irq: 100261bfbdb8SLars-Peter Clausen free_irq(host->irq, host); 100361bfbdb8SLars-Peter Clausen err_free_gpios: 100461bfbdb8SLars-Peter Clausen jz4740_mmc_free_gpios(pdev); 100561bfbdb8SLars-Peter Clausen err_gpio_bulk_free: 10067ca27a6fSApelete Seketeli if (host->use_dma) 10077ca27a6fSApelete Seketeli jz4740_mmc_release_dma_channels(host); 100861bfbdb8SLars-Peter Clausen jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 100961bfbdb8SLars-Peter Clausen err_free_host: 101061bfbdb8SLars-Peter Clausen mmc_free_host(mmc); 101161bfbdb8SLars-Peter Clausen 101261bfbdb8SLars-Peter Clausen return ret; 101361bfbdb8SLars-Peter Clausen } 101461bfbdb8SLars-Peter Clausen 10156e0ee714SBill Pemberton static int jz4740_mmc_remove(struct platform_device *pdev) 101661bfbdb8SLars-Peter Clausen { 101761bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = platform_get_drvdata(pdev); 101861bfbdb8SLars-Peter Clausen 101961bfbdb8SLars-Peter Clausen del_timer_sync(&host->timeout_timer); 102061bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, 0xff, false); 102161bfbdb8SLars-Peter Clausen jz4740_mmc_reset(host); 102261bfbdb8SLars-Peter Clausen 102361bfbdb8SLars-Peter Clausen mmc_remove_host(host->mmc); 102461bfbdb8SLars-Peter Clausen 102561bfbdb8SLars-Peter Clausen free_irq(host->irq, host); 102661bfbdb8SLars-Peter Clausen 102761bfbdb8SLars-Peter Clausen jz4740_mmc_free_gpios(pdev); 102861bfbdb8SLars-Peter Clausen jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 102961bfbdb8SLars-Peter Clausen 10307ca27a6fSApelete Seketeli if (host->use_dma) 10317ca27a6fSApelete Seketeli jz4740_mmc_release_dma_channels(host); 10327ca27a6fSApelete Seketeli 103361bfbdb8SLars-Peter Clausen mmc_free_host(host->mmc); 103461bfbdb8SLars-Peter Clausen 103561bfbdb8SLars-Peter Clausen return 0; 103661bfbdb8SLars-Peter Clausen } 103761bfbdb8SLars-Peter Clausen 10385d5c0350SLars-Peter Clausen #ifdef CONFIG_PM_SLEEP 103961bfbdb8SLars-Peter Clausen 104061bfbdb8SLars-Peter Clausen static int jz4740_mmc_suspend(struct device *dev) 104161bfbdb8SLars-Peter Clausen { 104261bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = dev_get_drvdata(dev); 104361bfbdb8SLars-Peter Clausen 104461bfbdb8SLars-Peter Clausen jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 104561bfbdb8SLars-Peter Clausen 104661bfbdb8SLars-Peter Clausen return 0; 104761bfbdb8SLars-Peter Clausen } 104861bfbdb8SLars-Peter Clausen 104961bfbdb8SLars-Peter Clausen static int jz4740_mmc_resume(struct device *dev) 105061bfbdb8SLars-Peter Clausen { 105161bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = dev_get_drvdata(dev); 105261bfbdb8SLars-Peter Clausen 105361bfbdb8SLars-Peter Clausen jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 105461bfbdb8SLars-Peter Clausen 105561bfbdb8SLars-Peter Clausen return 0; 105661bfbdb8SLars-Peter Clausen } 105761bfbdb8SLars-Peter Clausen 10585d5c0350SLars-Peter Clausen static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, 10595d5c0350SLars-Peter Clausen jz4740_mmc_resume); 106061bfbdb8SLars-Peter Clausen #define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops) 106161bfbdb8SLars-Peter Clausen #else 106261bfbdb8SLars-Peter Clausen #define JZ4740_MMC_PM_OPS NULL 106361bfbdb8SLars-Peter Clausen #endif 106461bfbdb8SLars-Peter Clausen 106561bfbdb8SLars-Peter Clausen static struct platform_driver jz4740_mmc_driver = { 106661bfbdb8SLars-Peter Clausen .probe = jz4740_mmc_probe, 10670433c143SBill Pemberton .remove = jz4740_mmc_remove, 106861bfbdb8SLars-Peter Clausen .driver = { 106961bfbdb8SLars-Peter Clausen .name = "jz4740-mmc", 107061bfbdb8SLars-Peter Clausen .owner = THIS_MODULE, 107161bfbdb8SLars-Peter Clausen .pm = JZ4740_MMC_PM_OPS, 107261bfbdb8SLars-Peter Clausen }, 107361bfbdb8SLars-Peter Clausen }; 107461bfbdb8SLars-Peter Clausen 1075d1f81a64SAxel Lin module_platform_driver(jz4740_mmc_driver); 107661bfbdb8SLars-Peter Clausen 107761bfbdb8SLars-Peter Clausen MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); 107861bfbdb8SLars-Peter Clausen MODULE_LICENSE("GPL"); 107961bfbdb8SLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1080