161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen/* 261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * JZ4740 SD/MMC controller driver 461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * 561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * This program is free software; you can redistribute it and/or modify it 661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * under the terms of the GNU General Public License as published by the 761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * Free Software Foundation; either version 2 of the License, or (at your 861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * option) any later version. 961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * 1061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * You should have received a copy of the GNU General Public License along 1161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * with this program; if not, write to the Free Software Foundation, Inc., 1261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * 675 Mass Ave, Cambridge, MA 02139, USA. 1361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * 1461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen */ 1561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 1661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/mmc/host.h> 1758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen#include <linux/mmc/slot-gpio.h> 183119cbda858fc9ae10a69919e5f278abd6d93bb5Jamie Iles#include <linux/err.h> 1961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/io.h> 2061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/irq.h> 2161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/interrupt.h> 2261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/module.h> 2361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/platform_device.h> 2461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/delay.h> 2561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/scatterlist.h> 2661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/clk.h> 2761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 2861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/bitops.h> 2961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/gpio.h> 3061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <asm/mach-jz4740/gpio.h> 3161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <asm/cacheflush.h> 3261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <linux/dma-mapping.h> 337ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli#include <linux/dmaengine.h> 3461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 357ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli#include <asm/mach-jz4740/dma.h> 3661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#include <asm/mach-jz4740/jz4740_mmc.h> 3761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 3861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_STRPCL 0x00 3961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_STATUS 0x04 4061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_CLKRT 0x08 4161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_CMDAT 0x0C 4261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RESTO 0x10 4361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RDTO 0x14 4461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_BLKLEN 0x18 4561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_NOB 0x1C 4661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_SNOB 0x20 4761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_IMASK 0x24 4861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_IREG 0x28 4961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_CMD 0x2C 5061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_ARG 0x30 5161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RESP_FIFO 0x34 5261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_RXFIFO 0x38 5361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_REG_MMC_TXFIFO 0x3C 5461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 5561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) 5661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6) 5761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_START_READWAIT BIT(5) 5861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_STOP_READWAIT BIT(4) 5961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_RESET BIT(3) 6061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_START_OP BIT(2) 6161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0)) 6261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_CLOCK_STOP BIT(0) 6361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STRPCL_CLOCK_START BIT(1) 6461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 6561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 6661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_IS_RESETTING BIT(15) 6761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14) 6861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_PRG_DONE BIT(13) 6961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12) 7061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_END_CMD_RES BIT(11) 7161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10) 7261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_IS_READWAIT BIT(9) 7361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CLK_EN BIT(8) 7461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7) 7561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6) 7661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CRC_RES_ERR BIT(5) 7761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4) 7861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3) 7961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2) 8061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_TIMEOUT_RES BIT(1) 8161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_TIMEOUT_READ BIT(0) 8261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 8361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0)) 8461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2)) 8561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 8661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 8761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_IO_ABORT BIT(11) 8861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10) 8961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_DMA_EN BIT(8) 9061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_INIT BIT(7) 9161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_BUSY BIT(6) 9261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_STREAM BIT(5) 9361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_WRITE BIT(4) 9461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_DATA_EN BIT(3) 9561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0)) 9661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RSP_R1 1 9761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RSP_R2 2 9861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CMDAT_RSP_R3 3 9961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 10061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_SDIO BIT(7) 10161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6) 10261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5) 10361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_END_CMD_RES BIT(2) 10461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_PRG_DONE BIT(1) 10561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0) 10661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 10761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 10861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ_MMC_CLK_RATE 24000000 10961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 11061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenenum jz4740_mmc_state { 11161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ4740_MMC_STATE_READ_RESPONSE, 11261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ4740_MMC_STATE_TRANSFER_DATA, 11361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ4740_MMC_STATE_SEND_STOP, 11461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ4740_MMC_STATE_DONE, 11561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}; 11661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 117bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistruct jz4740_mmc_host_next { 118bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli int sg_len; 119bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli s32 cookie; 120bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli}; 121bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 12261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstruct jz4740_mmc_host { 12361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_host *mmc; 12461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct platform_device *pdev; 12561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_platform_data *pdata; 12661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct clk *clk; 12761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 12861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int irq; 12961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int card_detect_irq; 13061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 13161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen void __iomem *base; 1327ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct resource *mem_res; 13361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_request *req; 13461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_command *cmd; 13561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 13661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned long waiting; 13761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 13861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint32_t cmdat; 13961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 14061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint16_t irq_mask; 14161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 14261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen spinlock_t lock; 14361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 14461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct timer_list timeout_timer; 14561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct sg_mapping_iter miter; 14661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen enum jz4740_mmc_state state; 1477ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1487ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli /* DMA support */ 1497ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct dma_chan *dma_rx; 1507ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct dma_chan *dma_tx; 151bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct jz4740_mmc_host_next next_data; 1527ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli bool use_dma; 1537ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli int sg_len; 1547ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1557ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/* The DMA trigger level is 8 words, that is to say, the DMA read 1567ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli * trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write 1577ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli * trigger is when data words in MSC_TXFIFO is < 8. 1587ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli */ 1597ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli#define JZ4740_MMC_FIFO_HALF_SIZE 8 16061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}; 16161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 1627ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/*----------------------------------------------------------------------------*/ 1637ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/* DMA infrastructure */ 1647ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1657ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host) 1667ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{ 1677ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (!host->use_dma) 1687ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli return; 1697ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1707ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_release_channel(host->dma_tx); 1717ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_release_channel(host->dma_rx); 1727ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli} 1737ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1747ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) 1757ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{ 1767ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_cap_mask_t mask; 1777ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1787ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_cap_zero(mask); 1797ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_cap_set(DMA_SLAVE, mask); 1807ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1817ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->dma_tx = dma_request_channel(mask, NULL, host); 1827ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (!host->dma_tx) { 1837ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n"); 1847ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli return -ENODEV; 1857ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli } 1867ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1877ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->dma_rx = dma_request_channel(mask, NULL, host); 1887ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (!host->dma_rx) { 1897ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n"); 1907ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli goto free_master_write; 1917ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli } 1927ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 193bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli /* Initialize DMA pre request cookie */ 194bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli host->next_data.cookie = 1; 195bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 1967ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli return 0; 1977ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 1987ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelifree_master_write: 1997ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_release_channel(host->dma_tx); 2007ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli return -ENODEV; 2017ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli} 2027ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 2037ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic inline int jz4740_mmc_get_dma_dir(struct mmc_data *data) 2047ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{ 2057ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli return (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 2067ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli} 2077ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 208bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host, 209bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct mmc_data *data) 210bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{ 211bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli return (data->flags & MMC_DATA_READ) ? host->dma_rx : host->dma_tx; 212bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli} 213bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 2147ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host, 2157ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct mmc_data *data) 2167ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{ 217bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data); 2187ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data); 2197ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 2207ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); 2217ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli} 2227ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 223bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli/* Prepares DMA data for current/next transfer, returns non-zero on failure */ 224bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host, 225bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct mmc_data *data, 226bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct jz4740_mmc_host_next *next, 227bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct dma_chan *chan) 228bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{ 229bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct jz4740_mmc_host_next *next_data = &host->next_data; 230bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data); 231bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli int sg_len; 232bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 233bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (!next && data->host_cookie && 234bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->host_cookie != host->next_data.cookie) { 235bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli dev_warn(mmc_dev(host->mmc), 236bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli "[%s] invalid cookie: data->host_cookie %d host->next_data.cookie %d\n", 237bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli __func__, 238bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->host_cookie, 239bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli host->next_data.cookie); 240bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->host_cookie = 0; 241bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } 242bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 243bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli /* Check if next job is already prepared */ 244bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (next || data->host_cookie != host->next_data.cookie) { 245bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli sg_len = dma_map_sg(chan->device->dev, 246bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->sg, 247bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->sg_len, 248bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli dir); 249bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 250bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } else { 251bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli sg_len = next_data->sg_len; 252bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli next_data->sg_len = 0; 253bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } 254bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 255bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (sg_len <= 0) { 256bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli dev_err(mmc_dev(host->mmc), 257bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli "Failed to map scatterlist for DMA operation\n"); 258bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli return -EINVAL; 259bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } 260bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 261bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (next) { 262bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli next->sg_len = sg_len; 263bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; 264bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } else 265bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli host->sg_len = sg_len; 266bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 267bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli return 0; 268bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli} 269bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 2707ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelistatic int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host, 2717ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct mmc_data *data) 2727ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli{ 273bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli int ret; 2747ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct dma_chan *chan; 2757ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct dma_async_tx_descriptor *desc; 2767ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct dma_slave_config conf = { 2777ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 2787ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 2797ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli .src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE, 2807ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli .dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE, 2817ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli }; 2827ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 283bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (data->flags & MMC_DATA_WRITE) { 2847ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.direction = DMA_MEM_TO_DEV; 2857ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO; 2867ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT; 2877ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli chan = host->dma_tx; 2887ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli } else { 2897ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.direction = DMA_DEV_TO_MEM; 2907ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO; 2917ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE; 2927ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli chan = host->dma_rx; 2937ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli } 2947ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 295bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli ret = jz4740_mmc_prepare_dma_data(host, data, NULL, chan); 296bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (ret) 297bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli return ret; 2987ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 2997ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dmaengine_slave_config(chan, &conf); 3007ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli desc = dmaengine_prep_slave_sg(chan, 3017ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli data->sg, 3027ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->sg_len, 3037ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.direction, 3047ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 3057ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (!desc) { 3067ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dev_err(mmc_dev(host->mmc), 3077ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli "Failed to allocate DMA %s descriptor", 3087ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli conf.direction == DMA_MEM_TO_DEV ? "TX" : "RX"); 3097ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli goto dma_unmap; 3107ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli } 3117ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 3127ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dmaengine_submit(desc); 3137ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dma_async_issue_pending(chan); 3147ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 3157ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli return 0; 3167ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 3177ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketelidma_unmap: 3187ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli jz4740_mmc_dma_unmap(host, data); 3197ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli return -ENOMEM; 3207ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli} 3217ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 322bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic void jz4740_mmc_pre_request(struct mmc_host *mmc, 323bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct mmc_request *mrq, 324bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli bool is_first_req) 325bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{ 326bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct jz4740_mmc_host *host = mmc_priv(mmc); 327bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct mmc_data *data = mrq->data; 328bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct jz4740_mmc_host_next *next_data = &host->next_data; 329bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 330bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli BUG_ON(data->host_cookie); 331bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 332bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (host->use_dma) { 333bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data); 334bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 335bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan)) 336bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->host_cookie = 0; 337bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } 338bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli} 339bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 340bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketelistatic void jz4740_mmc_post_request(struct mmc_host *mmc, 341bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct mmc_request *mrq, 342bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli int err) 343bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli{ 344bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct jz4740_mmc_host *host = mmc_priv(mmc); 345bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct mmc_data *data = mrq->data; 346bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 347bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (host->use_dma && data->host_cookie) { 348bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli jz4740_mmc_dma_unmap(host, data); 349bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli data->host_cookie = 0; 350bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } 351bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 352bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli if (err) { 353bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data); 354bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 355bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli dmaengine_terminate_all(chan); 356bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli } 357bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli} 358bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli 3597ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli/*----------------------------------------------------------------------------*/ 3607ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 36161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, 36261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned int irq, bool enabled) 36361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 36461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned long flags; 36561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 36661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen spin_lock_irqsave(&host->lock, flags); 36761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (enabled) 36861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->irq_mask &= ~irq; 36961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen else 37061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->irq_mask |= irq; 37161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen spin_unlock_irqrestore(&host->lock, flags); 37261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 37361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); 37461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 37561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 37661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, 37761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen bool start_transfer) 37861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 37961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint16_t val = JZ_MMC_STRPCL_CLOCK_START; 38061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 38161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (start_transfer) 38261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen val |= JZ_MMC_STRPCL_START_OP; 38361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 38461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(val, host->base + JZ_REG_MMC_STRPCL); 38561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 38661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 38761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host) 38861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 38961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint32_t status; 39061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned int timeout = 1000; 39161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 39261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL); 39361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen do { 39461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 39561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } while (status & JZ_MMC_STATUS_CLK_EN && --timeout); 39661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 39761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 39861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_reset(struct jz4740_mmc_host *host) 39961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 40061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint32_t status; 40161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned int timeout = 1000; 40261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 40361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL); 40461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen udelay(10); 40561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen do { 40661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 40761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout); 40861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 40961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 41061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_request_done(struct jz4740_mmc_host *host) 41161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 41261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_request *req; 41361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 41461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen req = host->req; 41561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->req = NULL; 41661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 41761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc_request_done(host->mmc, req); 41861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 41961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 42061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, 42161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned int irq) 42261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 42361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned int timeout = 0x800; 42461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint16_t status; 42561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 42661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen do { 42761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen status = readw(host->base + JZ_REG_MMC_IREG); 42861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } while (!(status & irq) && --timeout); 42961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 43061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (timeout == 0) { 43161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen set_bit(0, &host->waiting); 43261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mod_timer(&host->timeout_timer, jiffies + 5*HZ); 43361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_set_irq_enabled(host, irq, true); 43461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return true; 43561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 43661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 43761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return false; 43861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 43961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 44061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host, 44161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_data *data) 44261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 44361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int status; 44461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 44561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 44661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) { 44761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) { 44861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->req->cmd->error = -ETIMEDOUT; 44961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen data->error = -ETIMEDOUT; 45061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } else { 45161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->req->cmd->error = -EIO; 45261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen data->error = -EIO; 45361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 4548a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil } else if (status & JZ_MMC_STATUS_READ_ERROR_MASK) { 4558a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil if (status & (JZ_MMC_STATUS_TIMEOUT_READ)) { 4568a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil host->req->cmd->error = -ETIMEDOUT; 4578a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil data->error = -ETIMEDOUT; 4588a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil } else { 4598a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil host->req->cmd->error = -EIO; 4608a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil data->error = -EIO; 4618a489aa10cf84e54de812bd964f3520504460b94Paul Cercueil } 46261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 46361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 46461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 46561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic bool jz4740_mmc_write_data(struct jz4740_mmc_host *host, 46661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_data *data) 46761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 46861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct sg_mapping_iter *miter = &host->miter; 46961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO; 47061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint32_t *buf; 47161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen bool timeout; 47261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen size_t i, j; 47361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 47461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (sg_miter_next(miter)) { 47561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf = miter->addr; 47661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen i = miter->length / 4; 47761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen j = i / 8; 47861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen i = i & 0x7; 47961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (j) { 48061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); 48161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(timeout)) 48261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto poll_timeout; 48361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 48461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[0], fifo_addr); 48561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[1], fifo_addr); 48661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[2], fifo_addr); 48761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[3], fifo_addr); 48861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[4], fifo_addr); 48961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[5], fifo_addr); 49061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[6], fifo_addr); 49161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(buf[7], fifo_addr); 49261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf += 8; 49361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen --j; 49461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 49561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(i)) { 49661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); 49761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(timeout)) 49861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto poll_timeout; 49961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 50061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (i) { 50161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(*buf, fifo_addr); 50261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen ++buf; 50361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen --i; 50461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 50561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 50661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen data->bytes_xfered += miter->length; 50761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 50861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen sg_miter_stop(miter); 50961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 51061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return false; 51161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 51261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenpoll_timeout: 51361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen miter->consumed = (void *)buf - miter->addr; 51461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen data->bytes_xfered += miter->consumed; 51561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen sg_miter_stop(miter); 51661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 51761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return true; 51861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 51961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 52061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, 52161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_data *data) 52261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 52361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct sg_mapping_iter *miter = &host->miter; 52461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO; 52561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint32_t *buf; 52661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint32_t d; 52761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint16_t status; 52861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen size_t i, j; 52961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen unsigned int timeout; 53061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 53161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (sg_miter_next(miter)) { 53261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf = miter->addr; 53361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen i = miter->length; 53461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen j = i / 32; 53561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen i = i & 0x1f; 53661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (j) { 53761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); 53861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(timeout)) 53961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto poll_timeout; 54061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 54161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[0] = readl(fifo_addr); 54261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[1] = readl(fifo_addr); 54361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[2] = readl(fifo_addr); 54461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[3] = readl(fifo_addr); 54561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[4] = readl(fifo_addr); 54661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[5] = readl(fifo_addr); 54761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[6] = readl(fifo_addr); 54861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf[7] = readl(fifo_addr); 54961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 55061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen buf += 8; 55161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen --j; 55261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 55361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 55461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(i)) { 55561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); 55661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(timeout)) 55761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto poll_timeout; 55861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 55961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (i >= 4) { 56061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen *buf++ = readl(fifo_addr); 56161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen i -= 4; 56261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 56361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(i > 0)) { 56461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen d = readl(fifo_addr); 56561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen memcpy(buf, &d, i); 56661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 56761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 56861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen data->bytes_xfered += miter->length; 56961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 57061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen /* This can go away once MIPS implements 57161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * flush_kernel_dcache_page */ 57261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen flush_dcache_page(miter->page); 57361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 57461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen sg_miter_stop(miter); 57561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 57661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen /* For whatever reason there is sometime one word more in the fifo then 57761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen * requested */ 57861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen timeout = 1000; 57961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 58061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) { 58161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen d = readl(fifo_addr); 58261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 58361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 58461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 58561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return false; 58661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 58761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenpoll_timeout: 58861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen miter->consumed = (void *)buf - miter->addr; 58961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen data->bytes_xfered += miter->consumed; 59061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen sg_miter_stop(miter); 59161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 59261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return true; 59361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 59461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 59561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_timeout(unsigned long data) 59661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 59761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data; 59861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 59961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (!test_and_clear_bit(0, &host->waiting)) 60061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return; 60161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 60261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false); 60361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 60461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->req->cmd->error = -ETIMEDOUT; 60561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_request_done(host); 60661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 60761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 60861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_read_response(struct jz4740_mmc_host *host, 60961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_command *cmd) 61061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 61161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int i; 61261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint16_t tmp; 61361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO; 61461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 61561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->flags & MMC_RSP_136) { 61661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen tmp = readw(fifo_addr); 61761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen for (i = 0; i < 4; ++i) { 61861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->resp[i] = tmp << 24; 61961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen tmp = readw(fifo_addr); 62061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->resp[i] |= tmp << 8; 62161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen tmp = readw(fifo_addr); 62261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->resp[i] |= tmp >> 8; 62361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 62461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } else { 62561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->resp[0] = readw(fifo_addr) << 24; 62661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->resp[0] |= readw(fifo_addr) << 8; 62761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->resp[0] |= readw(fifo_addr) & 0xff; 62861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 62961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 63061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 63161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_send_command(struct jz4740_mmc_host *host, 63261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_command *cmd) 63361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 63461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint32_t cmdat = host->cmdat; 63561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 63661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->cmdat &= ~JZ_MMC_CMDAT_INIT; 63761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_clock_disable(host); 63861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 63961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->cmd = cmd; 64061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 64161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->flags & MMC_RSP_BUSY) 64261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmdat |= JZ_MMC_CMDAT_BUSY; 64361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 64461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen switch (mmc_resp_type(cmd)) { 64561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_RSP_R1B: 64661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_RSP_R1: 64761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R1; 64861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 64961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_RSP_R2: 65061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R2; 65161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 65261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_RSP_R3: 65361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R3; 65461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 65561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen default: 65661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 65761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 65861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 65961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->data) { 66061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmdat |= JZ_MMC_CMDAT_DATA_EN; 66161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->data->flags & MMC_DATA_WRITE) 66261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmdat |= JZ_MMC_CMDAT_WRITE; 66361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->data->flags & MMC_DATA_STREAM) 66461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmdat |= JZ_MMC_CMDAT_STREAM; 6657ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (host->use_dma) 6667ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli cmdat |= JZ_MMC_CMDAT_DMA_EN; 66761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 66861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN); 66961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB); 67061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 67161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 67261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD); 67361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(cmd->arg, host->base + JZ_REG_MMC_ARG); 67461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writel(cmdat, host->base + JZ_REG_MMC_CMDAT); 67561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 67661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_clock_enable(host, 1); 67761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 67861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 67961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host) 68061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 68161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_command *cmd = host->req->cmd; 68261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_data *data = cmd->data; 68361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int direction; 68461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 68561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (data->flags & MMC_DATA_READ) 68661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen direction = SG_MITER_TO_SG; 68761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen else 68861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen direction = SG_MITER_FROM_SG; 68961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 69061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen sg_miter_start(&host->miter, data->sg, data->sg_len, direction); 69161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 69261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 69361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 69461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic irqreturn_t jz_mmc_irq_worker(int irq, void *devid) 69561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 69661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid; 69761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_command *cmd = host->req->cmd; 69861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_request *req = host->req; 6997ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli struct mmc_data *data = cmd->data; 70061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen bool timeout = false; 70161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 70261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->error) 70361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->state = JZ4740_MMC_STATE_DONE; 70461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 70561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen switch (host->state) { 70661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case JZ4740_MMC_STATE_READ_RESPONSE: 70761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->flags & MMC_RSP_PRESENT) 70861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_read_response(host, cmd); 70961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 7107ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (!data) 71161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 71261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 71361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz_mmc_prepare_data_transfer(host); 71461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 71561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case JZ4740_MMC_STATE_TRANSFER_DATA: 7167ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (host->use_dma) { 717bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli /* Use DMA if enabled. 718bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli * Data transfer direction is defined later by 719bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli * relying on data flags in 720bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli * jz4740_mmc_prepare_dma_data() and 721bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli * jz4740_mmc_start_dma_transfer(). 7227ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli */ 7237ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli timeout = jz4740_mmc_start_dma_transfer(host, data); 7247ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli data->bytes_xfered = data->blocks * data->blksz; 7257ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli } else if (data->flags & MMC_DATA_READ) 726bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli /* Use PIO if DMA is not enabled. 727bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli * Data transfer direction was defined before 728bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli * by relying on data flags in 729bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli * jz_mmc_prepare_data_transfer(). 7307ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli */ 7317ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli timeout = jz4740_mmc_read_data(host, data); 73261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen else 7337ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli timeout = jz4740_mmc_write_data(host, data); 73461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 73561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(timeout)) { 73661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->state = JZ4740_MMC_STATE_TRANSFER_DATA; 73761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 73861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 73961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 7407ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli jz4740_mmc_transfer_check_state(host, data); 74161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 74261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE); 74361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (unlikely(timeout)) { 74461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->state = JZ4740_MMC_STATE_SEND_STOP; 74561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 74661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 74761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); 74861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 74961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case JZ4740_MMC_STATE_SEND_STOP: 75061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (!req->stop) 75161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 75261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 75361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_send_command(host, req->stop); 75461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 7551acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith if (mmc_resp_type(req->stop) & MMC_RSP_BUSY) { 7561acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith timeout = jz4740_mmc_poll_irq(host, 7571acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith JZ_MMC_IRQ_PRG_DONE); 7581acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith if (timeout) { 7591acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith host->state = JZ4740_MMC_STATE_DONE; 7601acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith break; 7611acee84b6fcfccb2f3488bfdf23664b47e0c445bAlex Smith } 76261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 76361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case JZ4740_MMC_STATE_DONE: 76461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 76561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 76661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 76761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (!timeout) 76861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_request_done(host); 76961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 77061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return IRQ_HANDLED; 77161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 77261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 77361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic irqreturn_t jz_mmc_irq(int irq, void *devid) 77461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 77561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = devid; 77661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_command *cmd = host->cmd; 77761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen uint16_t irq_reg, status, tmp; 77861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 77961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen irq_reg = readw(host->base + JZ_REG_MMC_IREG); 78061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 78161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen tmp = irq_reg; 78261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen irq_reg &= ~host->irq_mask; 78361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 78461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ | 78561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); 78661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 78761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (tmp != irq_reg) 78861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); 78961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 79061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (irq_reg & JZ_MMC_IRQ_SDIO) { 79161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG); 79261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc_signal_sdio_irq(host->mmc); 79361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen irq_reg &= ~JZ_MMC_IRQ_SDIO; 79461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 79561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 79661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (host->req && cmd && irq_reg) { 79761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (test_and_clear_bit(0, &host->waiting)) { 79861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen del_timer(&host->timeout_timer); 79961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 80061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 80161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 80261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (status & JZ_MMC_STATUS_TIMEOUT_RES) { 80361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->error = -ETIMEDOUT; 80461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { 80561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->error = -EIO; 80661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | 80761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_MMC_STATUS_CRC_WRITE_ERROR)) { 80861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (cmd->data) 80961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->data->error = -EIO; 81061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen cmd->error = -EIO; 81161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 81261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 81361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_set_irq_enabled(host, irq_reg, false); 81461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(irq_reg, host->base + JZ_REG_MMC_IREG); 81561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 81661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return IRQ_WAKE_THREAD; 81761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 81861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 81961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 82061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return IRQ_HANDLED; 82161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 82261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 82361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) 82461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 82561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int div = 0; 82661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int real_rate; 82761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 82861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_clock_disable(host); 82961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen clk_set_rate(host->clk, JZ_MMC_CLK_RATE); 83061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 83161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen real_rate = clk_get_rate(host->clk); 83261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 83361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen while (real_rate > rate && div < 7) { 83461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen ++div; 83561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen real_rate >>= 1; 83661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 83761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 83861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(div, host->base + JZ_REG_MMC_CLKRT); 83961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return real_rate; 84061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 84161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 84261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) 84361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 84461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 84561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 84661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->req = req; 84761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 84861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(0xffff, host->base + JZ_REG_MMC_IREG); 84961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 85061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); 85161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true); 85261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 85361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->state = JZ4740_MMC_STATE_READ_RESPONSE; 85461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen set_bit(0, &host->waiting); 85561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mod_timer(&host->timeout_timer, jiffies + 5*HZ); 85661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_send_command(host, req->cmd); 85761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 85861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 85961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 86061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 86161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 86261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (ios->clock) 86361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_set_clock_rate(host, ios->clock); 86461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 86561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen switch (ios->power_mode) { 86661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_POWER_UP: 86761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_reset(host); 86861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (gpio_is_valid(host->pdata->gpio_power)) 86961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen gpio_set_value(host->pdata->gpio_power, 87061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen !host->pdata->power_active_low); 87161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->cmdat |= JZ_MMC_CMDAT_INIT; 872fca9661c6c8926171a49f6ac57adc65290f10cafLars-Peter Clausen clk_prepare_enable(host->clk); 87361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 87461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_POWER_ON: 87561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 87661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen default: 87761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (gpio_is_valid(host->pdata->gpio_power)) 87861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen gpio_set_value(host->pdata->gpio_power, 87961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->pdata->power_active_low); 880fca9661c6c8926171a49f6ac57adc65290f10cafLars-Peter Clausen clk_disable_unprepare(host->clk); 88161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 88261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 88361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 88461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen switch (ios->bus_width) { 88561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_BUS_WIDTH_1: 88661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT; 88761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 88861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen case MMC_BUS_WIDTH_4: 88961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT; 89061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 89161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen default: 89261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen break; 89361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 89461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 89561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 89661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) 89761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 89861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 89961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable); 90061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 90161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 90261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic const struct mmc_host_ops jz4740_mmc_ops = { 90361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen .request = jz4740_mmc_request, 904bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli .pre_req = jz4740_mmc_pre_request, 905bb2f45927f8e0d1fc0633f65cc1f17a40c80bf24Apelete Seketeli .post_req = jz4740_mmc_post_request, 90661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen .set_ios = jz4740_mmc_set_ios, 90758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen .get_ro = mmc_gpio_get_ro, 90858e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen .get_cd = mmc_gpio_get_cd, 90961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen .enable_sdio_irq = jz4740_mmc_enable_sdio_irq, 91061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}; 91161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 91261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic const struct jz_gpio_bulk_request jz4740_mmc_pins[] = { 91361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_CMD), 91461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_CLK), 91561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA0), 91661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA1), 91761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA2), 91861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen JZ_GPIO_BULK_PIN(MSC_DATA3), 91961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}; 92061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 921c3be1efd41a97f93be390240387d356a07b664c7Bill Pembertonstatic int jz4740_mmc_request_gpio(struct device *dev, int gpio, 92261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen const char *name, bool output, int value) 92361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 92461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int ret; 92561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 92661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (!gpio_is_valid(gpio)) 92761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return 0; 92861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 92961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen ret = gpio_request(gpio, name); 93061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (ret) { 93161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_err(dev, "Failed to request %s gpio: %d\n", name, ret); 93261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return ret; 93361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 93461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 93561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (output) 93661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen gpio_direction_output(gpio, value); 93761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen else 93861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen gpio_direction_input(gpio); 93961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 94061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return 0; 94161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 94261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 94358e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausenstatic int jz4740_mmc_request_gpios(struct mmc_host *mmc, 94458e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen struct platform_device *pdev) 94561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 94661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; 94758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen int ret = 0; 94861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 94961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (!pdata) 95061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return 0; 95161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 95258e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen if (!pdata->card_detect_active_low) 95358e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; 95458e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen if (!pdata->read_only_active_low) 95558e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; 95661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 95758e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen if (gpio_is_valid(pdata->gpio_card_detect)) { 958214fc309d1387e822d606a33a10e31cacfe83520Laurent Pinchart ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0); 95958e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen if (ret) 96058e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen return ret; 96158e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen } 96261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 96358e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen if (gpio_is_valid(pdata->gpio_read_only)) { 96458e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only); 96558e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen if (ret) 96658e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen return ret; 96761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 96861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 96958e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power, 97058e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen "MMC read only", true, pdata->power_active_low); 97161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 97261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 97361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic void jz4740_mmc_free_gpios(struct platform_device *pdev) 97461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 97561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; 97661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 97761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (!pdata) 97861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return; 97961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 98061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (gpio_is_valid(pdata->gpio_power)) 98161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen gpio_free(pdata->gpio_power); 98261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 98361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 98461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host) 98561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 98661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins); 98761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (host->pdata && host->pdata->data_1bit) 98861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen num_pins -= 3; 98961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 99061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return num_pins; 99161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 99261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 993c3be1efd41a97f93be390240387d356a07b664c7Bill Pembertonstatic int jz4740_mmc_probe(struct platform_device* pdev) 99461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 99561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen int ret; 99661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct mmc_host *mmc; 99761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host; 99861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_platform_data *pdata; 99961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 100061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen pdata = pdev->dev.platform_data; 100161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 100261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); 100361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (!mmc) { 100461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_err(&pdev->dev, "Failed to alloc mmc host structure\n"); 100561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return -ENOMEM; 100661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 100761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 100861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host = mmc_priv(mmc); 100961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->pdata = pdata; 101061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 101161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->irq = platform_get_irq(pdev, 0); 101261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (host->irq < 0) { 101361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen ret = host->irq; 101461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); 101561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto err_free_host; 101661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 101761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 1018017d84bd45d1d2e584d01f3875aacbfa481aa95aLars-Peter Clausen host->clk = devm_clk_get(&pdev->dev, "mmc"); 10193119cbda858fc9ae10a69919e5f278abd6d93bb5Jamie Iles if (IS_ERR(host->clk)) { 10203119cbda858fc9ae10a69919e5f278abd6d93bb5Jamie Iles ret = PTR_ERR(host->clk); 102161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_err(&pdev->dev, "Failed to get mmc clock\n"); 102261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto err_free_host; 102361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 102461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 10257ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10267ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->base = devm_ioremap_resource(&pdev->dev, host->mem_res); 10273e7e8c18a15102c3042206c067356e6c39961725Wei Yongjun if (IS_ERR(host->base)) { 10283e7e8c18a15102c3042206c067356e6c39961725Wei Yongjun ret = PTR_ERR(host->base); 10297ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dev_err(&pdev->dev, "Failed to ioremap base memory\n"); 1030017d84bd45d1d2e584d01f3875aacbfa481aa95aLars-Peter Clausen goto err_free_host; 103161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 103261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 103361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 103461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (ret) { 103561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret); 1036017d84bd45d1d2e584d01f3875aacbfa481aa95aLars-Peter Clausen goto err_free_host; 103761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 103861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 103958e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen ret = jz4740_mmc_request_gpios(mmc, pdev); 104061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (ret) 104161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto err_gpio_bulk_free; 104261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 104361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->ops = &jz4740_mmc_ops; 104461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->f_min = JZ_MMC_CLK_RATE / 128; 104561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->f_max = JZ_MMC_CLK_RATE; 104661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 104761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA; 104861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->caps |= MMC_CAP_SDIO_IRQ; 104961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 105061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->max_blk_size = (1 << 10) - 1; 105161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->max_blk_count = (1 << 15) - 1; 105261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 105361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 1054a36274e0184193e393fb82957925c3981a6b0477Martin K. Petersen mmc->max_segs = 128; 105561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc->max_seg_size = mmc->max_req_size; 105661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 105761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->mmc = mmc; 105861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->pdev = pdev; 105961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen spin_lock_init(&host->lock); 106061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen host->irq_mask = 0xffff; 106161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 106261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, 106361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_name(&pdev->dev), host); 106461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (ret) { 106561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); 106658e300af8192d2f33d0e2dd47c9e31fb5d50c417Lars-Peter Clausen goto err_free_gpios; 106761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 106861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 106961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_reset(host); 107061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_clock_disable(host); 107161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen setup_timer(&host->timeout_timer, jz4740_mmc_timeout, 107261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen (unsigned long)host); 107361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen /* It is not important when it times out, it just needs to timeout. */ 107461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen set_timer_slack(&host->timeout_timer, HZ); 107561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 10767ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->use_dma = true; 10777ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0) 10787ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->use_dma = false; 10797ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 108061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen platform_set_drvdata(pdev, host); 108161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen ret = mmc_add_host(mmc); 108261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 108361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen if (ret) { 108461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret); 108561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen goto err_free_irq; 108661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen } 108761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); 108861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 10897ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli dev_info(&pdev->dev, "Using %s, %d-bit mode\n", 10907ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli host->use_dma ? "DMA" : "PIO", 10917ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1); 10927ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 109361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return 0; 109461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 109561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_free_irq: 109661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen free_irq(host->irq, host); 109761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_free_gpios: 109861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_free_gpios(pdev); 109961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_gpio_bulk_free: 11007ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (host->use_dma) 11017ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli jz4740_mmc_release_dma_channels(host); 110261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 110361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenerr_free_host: 110461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc_free_host(mmc); 110561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 110661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return ret; 110761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 110861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 11096e0ee714fdab0568c3487455951dea2673e9557fBill Pembertonstatic int jz4740_mmc_remove(struct platform_device *pdev) 111061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 111161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = platform_get_drvdata(pdev); 111261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 111361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen del_timer_sync(&host->timeout_timer); 111461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_set_irq_enabled(host, 0xff, false); 111561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_reset(host); 111661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 111761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc_remove_host(host->mmc); 111861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 111961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen free_irq(host->irq, host); 112061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 112161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz4740_mmc_free_gpios(pdev); 112261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 112361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 11247ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli if (host->use_dma) 11257ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli jz4740_mmc_release_dma_channels(host); 11267ca27a6f80a4042666a28977ff8ee3aa527c6cd4Apelete Seketeli 112761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen mmc_free_host(host->mmc); 112861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 112961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return 0; 113061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 113161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 11325d5c0350fc9533a1af3a43ee2331fec412679fcfLars-Peter Clausen#ifdef CONFIG_PM_SLEEP 113361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 113461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic int jz4740_mmc_suspend(struct device *dev) 113561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 113661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = dev_get_drvdata(dev); 113761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 113861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 113961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 114061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return 0; 114161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 114261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 114361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic int jz4740_mmc_resume(struct device *dev) 114461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen{ 114561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen struct jz4740_mmc_host *host = dev_get_drvdata(dev); 114661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 114761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); 114861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 114961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen return 0; 115061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen} 115161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 11525d5c0350fc9533a1af3a43ee2331fec412679fcfLars-Peter Clausenstatic SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, 11535d5c0350fc9533a1af3a43ee2331fec412679fcfLars-Peter Clausen jz4740_mmc_resume); 115461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops) 115561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#else 115661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#define JZ4740_MMC_PM_OPS NULL 115761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen#endif 115861bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 115961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausenstatic struct platform_driver jz4740_mmc_driver = { 116061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen .probe = jz4740_mmc_probe, 11610433c14356702e296f474f77ebd42f0a9d9a5487Bill Pemberton .remove = jz4740_mmc_remove, 116261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen .driver = { 116361bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen .name = "jz4740-mmc", 116461bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen .pm = JZ4740_MMC_PM_OPS, 116561bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen }, 116661bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen}; 116761bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 1168d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(jz4740_mmc_driver); 116961bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter Clausen 117061bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter ClausenMODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); 117161bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter ClausenMODULE_LICENSE("GPL"); 117261bfbdb856879cff583fe53b2ab6ae907faedee7Lars-Peter ClausenMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1173