161bfbdb8SLars-Peter Clausen /* 261bfbdb8SLars-Peter Clausen * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 36a78768aSAlex Smith * Copyright (C) 2013, Imagination Technologies 46a78768aSAlex Smith * 561bfbdb8SLars-Peter Clausen * JZ4740 SD/MMC controller driver 661bfbdb8SLars-Peter Clausen * 761bfbdb8SLars-Peter Clausen * This program is free software; you can redistribute it and/or modify it 861bfbdb8SLars-Peter Clausen * under the terms of the GNU General Public License as published by the 961bfbdb8SLars-Peter Clausen * Free Software Foundation; either version 2 of the License, or (at your 1061bfbdb8SLars-Peter Clausen * option) any later version. 1161bfbdb8SLars-Peter Clausen * 1261bfbdb8SLars-Peter Clausen * You should have received a copy of the GNU General Public License along 1361bfbdb8SLars-Peter Clausen * with this program; if not, write to the Free Software Foundation, Inc., 1461bfbdb8SLars-Peter Clausen * 675 Mass Ave, Cambridge, MA 02139, USA. 1561bfbdb8SLars-Peter Clausen * 1661bfbdb8SLars-Peter Clausen */ 1761bfbdb8SLars-Peter Clausen 187e7845f3SEzequiel Garcia #include <linux/bitops.h> 197e7845f3SEzequiel Garcia #include <linux/clk.h> 207e7845f3SEzequiel Garcia #include <linux/delay.h> 217e7845f3SEzequiel Garcia #include <linux/dmaengine.h> 227e7845f3SEzequiel Garcia #include <linux/dma-mapping.h> 233119cbdaSJamie Iles #include <linux/err.h> 247e7845f3SEzequiel Garcia #include <linux/gpio.h> 257e7845f3SEzequiel Garcia #include <linux/interrupt.h> 2661bfbdb8SLars-Peter Clausen #include <linux/io.h> 2761bfbdb8SLars-Peter Clausen #include <linux/irq.h> 287e7845f3SEzequiel Garcia #include <linux/mmc/host.h> 297e7845f3SEzequiel Garcia #include <linux/mmc/slot-gpio.h> 3061bfbdb8SLars-Peter Clausen #include <linux/module.h> 3161e11ebaSEzequiel Garcia #include <linux/of_device.h> 32fa5ed6bcSPaul Cercueil #include <linux/pinctrl/consumer.h> 3361bfbdb8SLars-Peter Clausen #include <linux/platform_device.h> 3461bfbdb8SLars-Peter Clausen #include <linux/scatterlist.h> 3561bfbdb8SLars-Peter Clausen 3661bfbdb8SLars-Peter Clausen #include <asm/cacheflush.h> 3761bfbdb8SLars-Peter Clausen 387ca27a6fSApelete Seketeli #include <asm/mach-jz4740/dma.h> 3961bfbdb8SLars-Peter Clausen #include <asm/mach-jz4740/jz4740_mmc.h> 4061bfbdb8SLars-Peter Clausen 4161bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_STRPCL 0x00 4261bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_STATUS 0x04 4361bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_CLKRT 0x08 4461bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_CMDAT 0x0C 4561bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RESTO 0x10 4661bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RDTO 0x14 4761bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_BLKLEN 0x18 4861bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_NOB 0x1C 4961bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_SNOB 0x20 5061bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_IMASK 0x24 5161bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_IREG 0x28 5261bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_CMD 0x2C 5361bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_ARG 0x30 5461bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RESP_FIFO 0x34 5561bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_RXFIFO 0x38 5661bfbdb8SLars-Peter Clausen #define JZ_REG_MMC_TXFIFO 0x3C 576a78768aSAlex Smith #define JZ_REG_MMC_DMAC 0x44 5861bfbdb8SLars-Peter Clausen 5961bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) 6061bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6) 6161bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_START_READWAIT BIT(5) 6261bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_STOP_READWAIT BIT(4) 6361bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_RESET BIT(3) 6461bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_START_OP BIT(2) 6561bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0)) 6661bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_CLOCK_STOP BIT(0) 6761bfbdb8SLars-Peter Clausen #define JZ_MMC_STRPCL_CLOCK_START BIT(1) 6861bfbdb8SLars-Peter Clausen 6961bfbdb8SLars-Peter Clausen 7061bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_IS_RESETTING BIT(15) 7161bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14) 7261bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_PRG_DONE BIT(13) 7361bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12) 7461bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_END_CMD_RES BIT(11) 7561bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10) 7661bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_IS_READWAIT BIT(9) 7761bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CLK_EN BIT(8) 7861bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7) 7961bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6) 8061bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CRC_RES_ERR BIT(5) 8161bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4) 8261bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3) 8361bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2) 8461bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_TIMEOUT_RES BIT(1) 8561bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_TIMEOUT_READ BIT(0) 8661bfbdb8SLars-Peter Clausen 8761bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0)) 8861bfbdb8SLars-Peter Clausen #define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2)) 8961bfbdb8SLars-Peter Clausen 9061bfbdb8SLars-Peter Clausen 9161bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_IO_ABORT BIT(11) 9261bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10) 9361bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_DMA_EN BIT(8) 9461bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_INIT BIT(7) 9561bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_BUSY BIT(6) 9661bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_STREAM BIT(5) 9761bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_WRITE BIT(4) 9861bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_DATA_EN BIT(3) 9961bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0)) 10061bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RSP_R1 1 10161bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RSP_R2 2 10261bfbdb8SLars-Peter Clausen #define JZ_MMC_CMDAT_RSP_R3 3 10361bfbdb8SLars-Peter Clausen 10461bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_SDIO BIT(7) 10561bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6) 10661bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5) 10761bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_END_CMD_RES BIT(2) 10861bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_PRG_DONE BIT(1) 10961bfbdb8SLars-Peter Clausen #define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0) 11061bfbdb8SLars-Peter Clausen 1116a78768aSAlex Smith #define JZ_MMC_DMAC_DMA_SEL BIT(1) 1126a78768aSAlex Smith #define JZ_MMC_DMAC_DMA_EN BIT(0) 11361bfbdb8SLars-Peter Clausen 11461bfbdb8SLars-Peter Clausen #define JZ_MMC_CLK_RATE 24000000 11561bfbdb8SLars-Peter Clausen 11661e11ebaSEzequiel Garcia enum jz4740_mmc_version { 11761e11ebaSEzequiel Garcia JZ_MMC_JZ4740, 1186a78768aSAlex Smith JZ_MMC_JZ4750, 1196a78768aSAlex Smith JZ_MMC_JZ4780, 12061e11ebaSEzequiel Garcia }; 12161e11ebaSEzequiel Garcia 12261bfbdb8SLars-Peter Clausen enum jz4740_mmc_state { 12361bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_READ_RESPONSE, 12461bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_TRANSFER_DATA, 12561bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_SEND_STOP, 12661bfbdb8SLars-Peter Clausen JZ4740_MMC_STATE_DONE, 12761bfbdb8SLars-Peter Clausen }; 12861bfbdb8SLars-Peter Clausen 129bb2f4592SApelete Seketeli struct jz4740_mmc_host_next { 130bb2f4592SApelete Seketeli int sg_len; 131bb2f4592SApelete Seketeli s32 cookie; 132bb2f4592SApelete Seketeli }; 133bb2f4592SApelete Seketeli 13461bfbdb8SLars-Peter Clausen struct jz4740_mmc_host { 13561bfbdb8SLars-Peter Clausen struct mmc_host *mmc; 13661bfbdb8SLars-Peter Clausen struct platform_device *pdev; 13761bfbdb8SLars-Peter Clausen struct jz4740_mmc_platform_data *pdata; 13861bfbdb8SLars-Peter Clausen struct clk *clk; 13961bfbdb8SLars-Peter Clausen 14061e11ebaSEzequiel Garcia enum jz4740_mmc_version version; 14161e11ebaSEzequiel Garcia 14261bfbdb8SLars-Peter Clausen int irq; 14361bfbdb8SLars-Peter Clausen int card_detect_irq; 14461bfbdb8SLars-Peter Clausen 14561bfbdb8SLars-Peter Clausen void __iomem *base; 1467ca27a6fSApelete Seketeli struct resource *mem_res; 14761bfbdb8SLars-Peter Clausen struct mmc_request *req; 14861bfbdb8SLars-Peter Clausen struct mmc_command *cmd; 14961bfbdb8SLars-Peter Clausen 15061bfbdb8SLars-Peter Clausen unsigned long waiting; 15161bfbdb8SLars-Peter Clausen 15261bfbdb8SLars-Peter Clausen uint32_t cmdat; 15361bfbdb8SLars-Peter Clausen 1546a78768aSAlex Smith uint32_t irq_mask; 15561bfbdb8SLars-Peter Clausen 15661bfbdb8SLars-Peter Clausen spinlock_t lock; 15761bfbdb8SLars-Peter Clausen 15861bfbdb8SLars-Peter Clausen struct timer_list timeout_timer; 15961bfbdb8SLars-Peter Clausen struct sg_mapping_iter miter; 16061bfbdb8SLars-Peter Clausen enum jz4740_mmc_state state; 1617ca27a6fSApelete Seketeli 1627ca27a6fSApelete Seketeli /* DMA support */ 1637ca27a6fSApelete Seketeli struct dma_chan *dma_rx; 1647ca27a6fSApelete Seketeli struct dma_chan *dma_tx; 165bb2f4592SApelete Seketeli struct jz4740_mmc_host_next next_data; 1667ca27a6fSApelete Seketeli bool use_dma; 1677ca27a6fSApelete Seketeli int sg_len; 1687ca27a6fSApelete Seketeli 1697ca27a6fSApelete Seketeli /* The DMA trigger level is 8 words, that is to say, the DMA read 1707ca27a6fSApelete Seketeli * trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write 1717ca27a6fSApelete Seketeli * trigger is when data words in MSC_TXFIFO is < 8. 1727ca27a6fSApelete Seketeli */ 1737ca27a6fSApelete Seketeli #define JZ4740_MMC_FIFO_HALF_SIZE 8 17461bfbdb8SLars-Peter Clausen }; 17561bfbdb8SLars-Peter Clausen 1766a78768aSAlex Smith static void jz4740_mmc_write_irq_mask(struct jz4740_mmc_host *host, 1776a78768aSAlex Smith uint32_t val) 1786a78768aSAlex Smith { 1796a78768aSAlex Smith if (host->version >= JZ_MMC_JZ4750) 1806a78768aSAlex Smith return writel(val, host->base + JZ_REG_MMC_IMASK); 1816a78768aSAlex Smith else 1826a78768aSAlex Smith return writew(val, host->base + JZ_REG_MMC_IMASK); 1836a78768aSAlex Smith } 1846a78768aSAlex Smith 1856a78768aSAlex Smith static void jz4740_mmc_write_irq_reg(struct jz4740_mmc_host *host, 1866a78768aSAlex Smith uint32_t val) 1876a78768aSAlex Smith { 1886a78768aSAlex Smith if (host->version >= JZ_MMC_JZ4780) 1896a78768aSAlex Smith return writel(val, host->base + JZ_REG_MMC_IREG); 1906a78768aSAlex Smith else 1916a78768aSAlex Smith return writew(val, host->base + JZ_REG_MMC_IREG); 1926a78768aSAlex Smith } 1936a78768aSAlex Smith 1946a78768aSAlex Smith static uint32_t jz4740_mmc_read_irq_reg(struct jz4740_mmc_host *host) 1956a78768aSAlex Smith { 1966a78768aSAlex Smith if (host->version >= JZ_MMC_JZ4780) 1976a78768aSAlex Smith return readl(host->base + JZ_REG_MMC_IREG); 1986a78768aSAlex Smith else 1996a78768aSAlex Smith return readw(host->base + JZ_REG_MMC_IREG); 2006a78768aSAlex Smith } 2016a78768aSAlex Smith 2027ca27a6fSApelete Seketeli /*----------------------------------------------------------------------------*/ 2037ca27a6fSApelete Seketeli /* DMA infrastructure */ 2047ca27a6fSApelete Seketeli 2057ca27a6fSApelete Seketeli static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host) 2067ca27a6fSApelete Seketeli { 2077ca27a6fSApelete Seketeli if (!host->use_dma) 2087ca27a6fSApelete Seketeli return; 2097ca27a6fSApelete Seketeli 2107ca27a6fSApelete Seketeli dma_release_channel(host->dma_tx); 2117ca27a6fSApelete Seketeli dma_release_channel(host->dma_rx); 2127ca27a6fSApelete Seketeli } 2137ca27a6fSApelete Seketeli 2147ca27a6fSApelete Seketeli static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) 2157ca27a6fSApelete Seketeli { 2167ca27a6fSApelete Seketeli dma_cap_mask_t mask; 2177ca27a6fSApelete Seketeli 2187ca27a6fSApelete Seketeli dma_cap_zero(mask); 2197ca27a6fSApelete Seketeli dma_cap_set(DMA_SLAVE, mask); 2207ca27a6fSApelete Seketeli 2217ca27a6fSApelete Seketeli host->dma_tx = dma_request_channel(mask, NULL, host); 2227ca27a6fSApelete Seketeli if (!host->dma_tx) { 2237ca27a6fSApelete Seketeli dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n"); 2247ca27a6fSApelete Seketeli return -ENODEV; 2257ca27a6fSApelete Seketeli } 2267ca27a6fSApelete Seketeli 2277ca27a6fSApelete Seketeli host->dma_rx = dma_request_channel(mask, NULL, host); 2287ca27a6fSApelete Seketeli if (!host->dma_rx) { 2297ca27a6fSApelete Seketeli dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n"); 2307ca27a6fSApelete Seketeli goto free_master_write; 2317ca27a6fSApelete Seketeli } 2327ca27a6fSApelete Seketeli 233bb2f4592SApelete Seketeli /* Initialize DMA pre request cookie */ 234bb2f4592SApelete Seketeli host->next_data.cookie = 1; 235bb2f4592SApelete Seketeli 2367ca27a6fSApelete Seketeli return 0; 2377ca27a6fSApelete Seketeli 2387ca27a6fSApelete Seketeli free_master_write: 2397ca27a6fSApelete Seketeli dma_release_channel(host->dma_tx); 2407ca27a6fSApelete Seketeli return -ENODEV; 2417ca27a6fSApelete Seketeli } 2427ca27a6fSApelete Seketeli 243bb2f4592SApelete Seketeli static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host, 244bb2f4592SApelete Seketeli struct mmc_data *data) 245bb2f4592SApelete Seketeli { 246bb2f4592SApelete Seketeli return (data->flags & MMC_DATA_READ) ? host->dma_rx : host->dma_tx; 247bb2f4592SApelete Seketeli } 248bb2f4592SApelete Seketeli 2497ca27a6fSApelete Seketeli static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host, 2507ca27a6fSApelete Seketeli struct mmc_data *data) 2517ca27a6fSApelete Seketeli { 252bb2f4592SApelete Seketeli struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data); 253feeef096SHeiner Kallweit enum dma_data_direction dir = mmc_get_dma_dir(data); 2547ca27a6fSApelete Seketeli 2557ca27a6fSApelete Seketeli dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); 2567ca27a6fSApelete Seketeli } 2577ca27a6fSApelete Seketeli 258bb2f4592SApelete Seketeli /* Prepares DMA data for current/next transfer, returns non-zero on failure */ 259bb2f4592SApelete Seketeli static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host, 260bb2f4592SApelete Seketeli struct mmc_data *data, 261bb2f4592SApelete Seketeli struct jz4740_mmc_host_next *next, 262bb2f4592SApelete Seketeli struct dma_chan *chan) 263bb2f4592SApelete Seketeli { 264bb2f4592SApelete Seketeli struct jz4740_mmc_host_next *next_data = &host->next_data; 265feeef096SHeiner Kallweit enum dma_data_direction dir = mmc_get_dma_dir(data); 266bb2f4592SApelete Seketeli int sg_len; 267bb2f4592SApelete Seketeli 268bb2f4592SApelete Seketeli if (!next && data->host_cookie && 269bb2f4592SApelete Seketeli data->host_cookie != host->next_data.cookie) { 270bb2f4592SApelete Seketeli dev_warn(mmc_dev(host->mmc), 271bb2f4592SApelete Seketeli "[%s] invalid cookie: data->host_cookie %d host->next_data.cookie %d\n", 272bb2f4592SApelete Seketeli __func__, 273bb2f4592SApelete Seketeli data->host_cookie, 274bb2f4592SApelete Seketeli host->next_data.cookie); 275bb2f4592SApelete Seketeli data->host_cookie = 0; 276bb2f4592SApelete Seketeli } 277bb2f4592SApelete Seketeli 278bb2f4592SApelete Seketeli /* Check if next job is already prepared */ 279bb2f4592SApelete Seketeli if (next || data->host_cookie != host->next_data.cookie) { 280bb2f4592SApelete Seketeli sg_len = dma_map_sg(chan->device->dev, 281bb2f4592SApelete Seketeli data->sg, 282bb2f4592SApelete Seketeli data->sg_len, 283bb2f4592SApelete Seketeli dir); 284bb2f4592SApelete Seketeli 285bb2f4592SApelete Seketeli } else { 286bb2f4592SApelete Seketeli sg_len = next_data->sg_len; 287bb2f4592SApelete Seketeli next_data->sg_len = 0; 288bb2f4592SApelete Seketeli } 289bb2f4592SApelete Seketeli 290bb2f4592SApelete Seketeli if (sg_len <= 0) { 291bb2f4592SApelete Seketeli dev_err(mmc_dev(host->mmc), 292bb2f4592SApelete Seketeli "Failed to map scatterlist for DMA operation\n"); 293bb2f4592SApelete Seketeli return -EINVAL; 294bb2f4592SApelete Seketeli } 295bb2f4592SApelete Seketeli 296bb2f4592SApelete Seketeli if (next) { 297bb2f4592SApelete Seketeli next->sg_len = sg_len; 298bb2f4592SApelete Seketeli data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; 299bb2f4592SApelete Seketeli } else 300bb2f4592SApelete Seketeli host->sg_len = sg_len; 301bb2f4592SApelete Seketeli 302bb2f4592SApelete Seketeli return 0; 303bb2f4592SApelete Seketeli } 304bb2f4592SApelete Seketeli 3057ca27a6fSApelete Seketeli static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host, 3067ca27a6fSApelete Seketeli struct mmc_data *data) 3077ca27a6fSApelete Seketeli { 308bb2f4592SApelete Seketeli int ret; 3097ca27a6fSApelete Seketeli struct dma_chan *chan; 3107ca27a6fSApelete Seketeli struct dma_async_tx_descriptor *desc; 3117ca27a6fSApelete Seketeli struct dma_slave_config conf = { 3127ca27a6fSApelete Seketeli .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 3137ca27a6fSApelete Seketeli .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 3147ca27a6fSApelete Seketeli .src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE, 3157ca27a6fSApelete Seketeli .dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE, 3167ca27a6fSApelete Seketeli }; 3177ca27a6fSApelete Seketeli 318bb2f4592SApelete Seketeli if (data->flags & MMC_DATA_WRITE) { 3197ca27a6fSApelete Seketeli conf.direction = DMA_MEM_TO_DEV; 3207ca27a6fSApelete Seketeli conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO; 3217ca27a6fSApelete Seketeli conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT; 3227ca27a6fSApelete Seketeli chan = host->dma_tx; 3237ca27a6fSApelete Seketeli } else { 3247ca27a6fSApelete Seketeli conf.direction = DMA_DEV_TO_MEM; 3257ca27a6fSApelete Seketeli conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO; 3267ca27a6fSApelete Seketeli conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE; 3277ca27a6fSApelete Seketeli chan = host->dma_rx; 3287ca27a6fSApelete Seketeli } 3297ca27a6fSApelete Seketeli 330bb2f4592SApelete Seketeli ret = jz4740_mmc_prepare_dma_data(host, data, NULL, chan); 331bb2f4592SApelete Seketeli if (ret) 332bb2f4592SApelete Seketeli return ret; 3337ca27a6fSApelete Seketeli 3347ca27a6fSApelete Seketeli dmaengine_slave_config(chan, &conf); 3357ca27a6fSApelete Seketeli desc = dmaengine_prep_slave_sg(chan, 3367ca27a6fSApelete Seketeli data->sg, 3377ca27a6fSApelete Seketeli host->sg_len, 3387ca27a6fSApelete Seketeli conf.direction, 3397ca27a6fSApelete Seketeli DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 3407ca27a6fSApelete Seketeli if (!desc) { 3417ca27a6fSApelete Seketeli dev_err(mmc_dev(host->mmc), 3427ca27a6fSApelete Seketeli "Failed to allocate DMA %s descriptor", 3437ca27a6fSApelete Seketeli conf.direction == DMA_MEM_TO_DEV ? "TX" : "RX"); 3447ca27a6fSApelete Seketeli goto dma_unmap; 3457ca27a6fSApelete Seketeli } 3467ca27a6fSApelete Seketeli 3477ca27a6fSApelete Seketeli dmaengine_submit(desc); 3487ca27a6fSApelete Seketeli dma_async_issue_pending(chan); 3497ca27a6fSApelete Seketeli 3507ca27a6fSApelete Seketeli return 0; 3517ca27a6fSApelete Seketeli 3527ca27a6fSApelete Seketeli dma_unmap: 3537ca27a6fSApelete Seketeli jz4740_mmc_dma_unmap(host, data); 3547ca27a6fSApelete Seketeli return -ENOMEM; 3557ca27a6fSApelete Seketeli } 3567ca27a6fSApelete Seketeli 357bb2f4592SApelete Seketeli static void jz4740_mmc_pre_request(struct mmc_host *mmc, 358d3c6aac3SLinus Walleij struct mmc_request *mrq) 359bb2f4592SApelete Seketeli { 360bb2f4592SApelete Seketeli struct jz4740_mmc_host *host = mmc_priv(mmc); 361bb2f4592SApelete Seketeli struct mmc_data *data = mrq->data; 362bb2f4592SApelete Seketeli struct jz4740_mmc_host_next *next_data = &host->next_data; 363bb2f4592SApelete Seketeli 364bb2f4592SApelete Seketeli BUG_ON(data->host_cookie); 365bb2f4592SApelete Seketeli 366bb2f4592SApelete Seketeli if (host->use_dma) { 367bb2f4592SApelete Seketeli struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data); 368bb2f4592SApelete Seketeli 369bb2f4592SApelete Seketeli if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan)) 370bb2f4592SApelete Seketeli data->host_cookie = 0; 371bb2f4592SApelete Seketeli } 372bb2f4592SApelete Seketeli } 373bb2f4592SApelete Seketeli 374bb2f4592SApelete Seketeli static void jz4740_mmc_post_request(struct mmc_host *mmc, 375bb2f4592SApelete Seketeli struct mmc_request *mrq, 376bb2f4592SApelete Seketeli int err) 377bb2f4592SApelete Seketeli { 378bb2f4592SApelete Seketeli struct jz4740_mmc_host *host = mmc_priv(mmc); 379bb2f4592SApelete Seketeli struct mmc_data *data = mrq->data; 380bb2f4592SApelete Seketeli 381bb2f4592SApelete Seketeli if (host->use_dma && data->host_cookie) { 382bb2f4592SApelete Seketeli jz4740_mmc_dma_unmap(host, data); 383bb2f4592SApelete Seketeli data->host_cookie = 0; 384bb2f4592SApelete Seketeli } 385bb2f4592SApelete Seketeli 386bb2f4592SApelete Seketeli if (err) { 387bb2f4592SApelete Seketeli struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data); 388bb2f4592SApelete Seketeli 389bb2f4592SApelete Seketeli dmaengine_terminate_all(chan); 390bb2f4592SApelete Seketeli } 391bb2f4592SApelete Seketeli } 392bb2f4592SApelete Seketeli 3937ca27a6fSApelete Seketeli /*----------------------------------------------------------------------------*/ 3947ca27a6fSApelete Seketeli 39561bfbdb8SLars-Peter Clausen static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, 39661bfbdb8SLars-Peter Clausen unsigned int irq, bool enabled) 39761bfbdb8SLars-Peter Clausen { 39861bfbdb8SLars-Peter Clausen unsigned long flags; 39961bfbdb8SLars-Peter Clausen 40061bfbdb8SLars-Peter Clausen spin_lock_irqsave(&host->lock, flags); 40161bfbdb8SLars-Peter Clausen if (enabled) 40261bfbdb8SLars-Peter Clausen host->irq_mask &= ~irq; 40361bfbdb8SLars-Peter Clausen else 40461bfbdb8SLars-Peter Clausen host->irq_mask |= irq; 40561bfbdb8SLars-Peter Clausen 4066a78768aSAlex Smith jz4740_mmc_write_irq_mask(host, host->irq_mask); 407a04f0017SAlex Smith spin_unlock_irqrestore(&host->lock, flags); 40861bfbdb8SLars-Peter Clausen } 40961bfbdb8SLars-Peter Clausen 41061bfbdb8SLars-Peter Clausen static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, 41161bfbdb8SLars-Peter Clausen bool start_transfer) 41261bfbdb8SLars-Peter Clausen { 41361bfbdb8SLars-Peter Clausen uint16_t val = JZ_MMC_STRPCL_CLOCK_START; 41461bfbdb8SLars-Peter Clausen 41561bfbdb8SLars-Peter Clausen if (start_transfer) 41661bfbdb8SLars-Peter Clausen val |= JZ_MMC_STRPCL_START_OP; 41761bfbdb8SLars-Peter Clausen 41861bfbdb8SLars-Peter Clausen writew(val, host->base + JZ_REG_MMC_STRPCL); 41961bfbdb8SLars-Peter Clausen } 42061bfbdb8SLars-Peter Clausen 42161bfbdb8SLars-Peter Clausen static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host) 42261bfbdb8SLars-Peter Clausen { 42361bfbdb8SLars-Peter Clausen uint32_t status; 42461bfbdb8SLars-Peter Clausen unsigned int timeout = 1000; 42561bfbdb8SLars-Peter Clausen 42661bfbdb8SLars-Peter Clausen writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL); 42761bfbdb8SLars-Peter Clausen do { 42861bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 42961bfbdb8SLars-Peter Clausen } while (status & JZ_MMC_STATUS_CLK_EN && --timeout); 43061bfbdb8SLars-Peter Clausen } 43161bfbdb8SLars-Peter Clausen 43261bfbdb8SLars-Peter Clausen static void jz4740_mmc_reset(struct jz4740_mmc_host *host) 43361bfbdb8SLars-Peter Clausen { 43461bfbdb8SLars-Peter Clausen uint32_t status; 43561bfbdb8SLars-Peter Clausen unsigned int timeout = 1000; 43661bfbdb8SLars-Peter Clausen 43761bfbdb8SLars-Peter Clausen writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL); 43861bfbdb8SLars-Peter Clausen udelay(10); 43961bfbdb8SLars-Peter Clausen do { 44061bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 44161bfbdb8SLars-Peter Clausen } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout); 44261bfbdb8SLars-Peter Clausen } 44361bfbdb8SLars-Peter Clausen 44461bfbdb8SLars-Peter Clausen static void jz4740_mmc_request_done(struct jz4740_mmc_host *host) 44561bfbdb8SLars-Peter Clausen { 44661bfbdb8SLars-Peter Clausen struct mmc_request *req; 44761bfbdb8SLars-Peter Clausen 44861bfbdb8SLars-Peter Clausen req = host->req; 44961bfbdb8SLars-Peter Clausen host->req = NULL; 45061bfbdb8SLars-Peter Clausen 45161bfbdb8SLars-Peter Clausen mmc_request_done(host->mmc, req); 45261bfbdb8SLars-Peter Clausen } 45361bfbdb8SLars-Peter Clausen 45461bfbdb8SLars-Peter Clausen static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, 45561bfbdb8SLars-Peter Clausen unsigned int irq) 45661bfbdb8SLars-Peter Clausen { 45761bfbdb8SLars-Peter Clausen unsigned int timeout = 0x800; 4586a78768aSAlex Smith uint32_t status; 45961bfbdb8SLars-Peter Clausen 46061bfbdb8SLars-Peter Clausen do { 4616a78768aSAlex Smith status = jz4740_mmc_read_irq_reg(host); 46261bfbdb8SLars-Peter Clausen } while (!(status & irq) && --timeout); 46361bfbdb8SLars-Peter Clausen 46461bfbdb8SLars-Peter Clausen if (timeout == 0) { 46561bfbdb8SLars-Peter Clausen set_bit(0, &host->waiting); 46661bfbdb8SLars-Peter Clausen mod_timer(&host->timeout_timer, jiffies + 5*HZ); 46761bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, irq, true); 46861bfbdb8SLars-Peter Clausen return true; 46961bfbdb8SLars-Peter Clausen } 47061bfbdb8SLars-Peter Clausen 47161bfbdb8SLars-Peter Clausen return false; 47261bfbdb8SLars-Peter Clausen } 47361bfbdb8SLars-Peter Clausen 47461bfbdb8SLars-Peter Clausen static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host, 47561bfbdb8SLars-Peter Clausen struct mmc_data *data) 47661bfbdb8SLars-Peter Clausen { 47761bfbdb8SLars-Peter Clausen int status; 47861bfbdb8SLars-Peter Clausen 47961bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 48061bfbdb8SLars-Peter Clausen if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) { 48161bfbdb8SLars-Peter Clausen if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) { 48261bfbdb8SLars-Peter Clausen host->req->cmd->error = -ETIMEDOUT; 48361bfbdb8SLars-Peter Clausen data->error = -ETIMEDOUT; 48461bfbdb8SLars-Peter Clausen } else { 48561bfbdb8SLars-Peter Clausen host->req->cmd->error = -EIO; 48661bfbdb8SLars-Peter Clausen data->error = -EIO; 48761bfbdb8SLars-Peter Clausen } 4888a489aa1SPaul Cercueil } else if (status & JZ_MMC_STATUS_READ_ERROR_MASK) { 4898a489aa1SPaul Cercueil if (status & (JZ_MMC_STATUS_TIMEOUT_READ)) { 4908a489aa1SPaul Cercueil host->req->cmd->error = -ETIMEDOUT; 4918a489aa1SPaul Cercueil data->error = -ETIMEDOUT; 4928a489aa1SPaul Cercueil } else { 4938a489aa1SPaul Cercueil host->req->cmd->error = -EIO; 4948a489aa1SPaul Cercueil data->error = -EIO; 4958a489aa1SPaul Cercueil } 49661bfbdb8SLars-Peter Clausen } 49761bfbdb8SLars-Peter Clausen } 49861bfbdb8SLars-Peter Clausen 49961bfbdb8SLars-Peter Clausen static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host, 50061bfbdb8SLars-Peter Clausen struct mmc_data *data) 50161bfbdb8SLars-Peter Clausen { 50261bfbdb8SLars-Peter Clausen struct sg_mapping_iter *miter = &host->miter; 50361bfbdb8SLars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO; 50461bfbdb8SLars-Peter Clausen uint32_t *buf; 50561bfbdb8SLars-Peter Clausen bool timeout; 50661bfbdb8SLars-Peter Clausen size_t i, j; 50761bfbdb8SLars-Peter Clausen 50861bfbdb8SLars-Peter Clausen while (sg_miter_next(miter)) { 50961bfbdb8SLars-Peter Clausen buf = miter->addr; 51061bfbdb8SLars-Peter Clausen i = miter->length / 4; 51161bfbdb8SLars-Peter Clausen j = i / 8; 51261bfbdb8SLars-Peter Clausen i = i & 0x7; 51361bfbdb8SLars-Peter Clausen while (j) { 51461bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); 51561bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 51661bfbdb8SLars-Peter Clausen goto poll_timeout; 51761bfbdb8SLars-Peter Clausen 51861bfbdb8SLars-Peter Clausen writel(buf[0], fifo_addr); 51961bfbdb8SLars-Peter Clausen writel(buf[1], fifo_addr); 52061bfbdb8SLars-Peter Clausen writel(buf[2], fifo_addr); 52161bfbdb8SLars-Peter Clausen writel(buf[3], fifo_addr); 52261bfbdb8SLars-Peter Clausen writel(buf[4], fifo_addr); 52361bfbdb8SLars-Peter Clausen writel(buf[5], fifo_addr); 52461bfbdb8SLars-Peter Clausen writel(buf[6], fifo_addr); 52561bfbdb8SLars-Peter Clausen writel(buf[7], fifo_addr); 52661bfbdb8SLars-Peter Clausen buf += 8; 52761bfbdb8SLars-Peter Clausen --j; 52861bfbdb8SLars-Peter Clausen } 52961bfbdb8SLars-Peter Clausen if (unlikely(i)) { 53061bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ); 53161bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 53261bfbdb8SLars-Peter Clausen goto poll_timeout; 53361bfbdb8SLars-Peter Clausen 53461bfbdb8SLars-Peter Clausen while (i) { 53561bfbdb8SLars-Peter Clausen writel(*buf, fifo_addr); 53661bfbdb8SLars-Peter Clausen ++buf; 53761bfbdb8SLars-Peter Clausen --i; 53861bfbdb8SLars-Peter Clausen } 53961bfbdb8SLars-Peter Clausen } 54061bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->length; 54161bfbdb8SLars-Peter Clausen } 54261bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 54361bfbdb8SLars-Peter Clausen 54461bfbdb8SLars-Peter Clausen return false; 54561bfbdb8SLars-Peter Clausen 54661bfbdb8SLars-Peter Clausen poll_timeout: 54761bfbdb8SLars-Peter Clausen miter->consumed = (void *)buf - miter->addr; 54861bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->consumed; 54961bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 55061bfbdb8SLars-Peter Clausen 55161bfbdb8SLars-Peter Clausen return true; 55261bfbdb8SLars-Peter Clausen } 55361bfbdb8SLars-Peter Clausen 55461bfbdb8SLars-Peter Clausen static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, 55561bfbdb8SLars-Peter Clausen struct mmc_data *data) 55661bfbdb8SLars-Peter Clausen { 55761bfbdb8SLars-Peter Clausen struct sg_mapping_iter *miter = &host->miter; 55861bfbdb8SLars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO; 55961bfbdb8SLars-Peter Clausen uint32_t *buf; 56061bfbdb8SLars-Peter Clausen uint32_t d; 5616a78768aSAlex Smith uint32_t status; 56261bfbdb8SLars-Peter Clausen size_t i, j; 56361bfbdb8SLars-Peter Clausen unsigned int timeout; 56461bfbdb8SLars-Peter Clausen 56561bfbdb8SLars-Peter Clausen while (sg_miter_next(miter)) { 56661bfbdb8SLars-Peter Clausen buf = miter->addr; 56761bfbdb8SLars-Peter Clausen i = miter->length; 56861bfbdb8SLars-Peter Clausen j = i / 32; 56961bfbdb8SLars-Peter Clausen i = i & 0x1f; 57061bfbdb8SLars-Peter Clausen while (j) { 57161bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); 57261bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 57361bfbdb8SLars-Peter Clausen goto poll_timeout; 57461bfbdb8SLars-Peter Clausen 57561bfbdb8SLars-Peter Clausen buf[0] = readl(fifo_addr); 57661bfbdb8SLars-Peter Clausen buf[1] = readl(fifo_addr); 57761bfbdb8SLars-Peter Clausen buf[2] = readl(fifo_addr); 57861bfbdb8SLars-Peter Clausen buf[3] = readl(fifo_addr); 57961bfbdb8SLars-Peter Clausen buf[4] = readl(fifo_addr); 58061bfbdb8SLars-Peter Clausen buf[5] = readl(fifo_addr); 58161bfbdb8SLars-Peter Clausen buf[6] = readl(fifo_addr); 58261bfbdb8SLars-Peter Clausen buf[7] = readl(fifo_addr); 58361bfbdb8SLars-Peter Clausen 58461bfbdb8SLars-Peter Clausen buf += 8; 58561bfbdb8SLars-Peter Clausen --j; 58661bfbdb8SLars-Peter Clausen } 58761bfbdb8SLars-Peter Clausen 58861bfbdb8SLars-Peter Clausen if (unlikely(i)) { 58961bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ); 59061bfbdb8SLars-Peter Clausen if (unlikely(timeout)) 59161bfbdb8SLars-Peter Clausen goto poll_timeout; 59261bfbdb8SLars-Peter Clausen 59361bfbdb8SLars-Peter Clausen while (i >= 4) { 59461bfbdb8SLars-Peter Clausen *buf++ = readl(fifo_addr); 59561bfbdb8SLars-Peter Clausen i -= 4; 59661bfbdb8SLars-Peter Clausen } 59761bfbdb8SLars-Peter Clausen if (unlikely(i > 0)) { 59861bfbdb8SLars-Peter Clausen d = readl(fifo_addr); 59961bfbdb8SLars-Peter Clausen memcpy(buf, &d, i); 60061bfbdb8SLars-Peter Clausen } 60161bfbdb8SLars-Peter Clausen } 60261bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->length; 60361bfbdb8SLars-Peter Clausen 60461bfbdb8SLars-Peter Clausen /* This can go away once MIPS implements 60561bfbdb8SLars-Peter Clausen * flush_kernel_dcache_page */ 60661bfbdb8SLars-Peter Clausen flush_dcache_page(miter->page); 60761bfbdb8SLars-Peter Clausen } 60861bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 60961bfbdb8SLars-Peter Clausen 61061bfbdb8SLars-Peter Clausen /* For whatever reason there is sometime one word more in the fifo then 61161bfbdb8SLars-Peter Clausen * requested */ 61261bfbdb8SLars-Peter Clausen timeout = 1000; 61361bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 61461bfbdb8SLars-Peter Clausen while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) { 61561bfbdb8SLars-Peter Clausen d = readl(fifo_addr); 61661bfbdb8SLars-Peter Clausen status = readl(host->base + JZ_REG_MMC_STATUS); 61761bfbdb8SLars-Peter Clausen } 61861bfbdb8SLars-Peter Clausen 61961bfbdb8SLars-Peter Clausen return false; 62061bfbdb8SLars-Peter Clausen 62161bfbdb8SLars-Peter Clausen poll_timeout: 62261bfbdb8SLars-Peter Clausen miter->consumed = (void *)buf - miter->addr; 62361bfbdb8SLars-Peter Clausen data->bytes_xfered += miter->consumed; 62461bfbdb8SLars-Peter Clausen sg_miter_stop(miter); 62561bfbdb8SLars-Peter Clausen 62661bfbdb8SLars-Peter Clausen return true; 62761bfbdb8SLars-Peter Clausen } 62861bfbdb8SLars-Peter Clausen 6292ee4f620SKees Cook static void jz4740_mmc_timeout(struct timer_list *t) 63061bfbdb8SLars-Peter Clausen { 6312ee4f620SKees Cook struct jz4740_mmc_host *host = from_timer(host, t, timeout_timer); 63261bfbdb8SLars-Peter Clausen 63361bfbdb8SLars-Peter Clausen if (!test_and_clear_bit(0, &host->waiting)) 63461bfbdb8SLars-Peter Clausen return; 63561bfbdb8SLars-Peter Clausen 63661bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false); 63761bfbdb8SLars-Peter Clausen 63861bfbdb8SLars-Peter Clausen host->req->cmd->error = -ETIMEDOUT; 63961bfbdb8SLars-Peter Clausen jz4740_mmc_request_done(host); 64061bfbdb8SLars-Peter Clausen } 64161bfbdb8SLars-Peter Clausen 64261bfbdb8SLars-Peter Clausen static void jz4740_mmc_read_response(struct jz4740_mmc_host *host, 64361bfbdb8SLars-Peter Clausen struct mmc_command *cmd) 64461bfbdb8SLars-Peter Clausen { 64561bfbdb8SLars-Peter Clausen int i; 64661bfbdb8SLars-Peter Clausen uint16_t tmp; 64761bfbdb8SLars-Peter Clausen void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO; 64861bfbdb8SLars-Peter Clausen 64961bfbdb8SLars-Peter Clausen if (cmd->flags & MMC_RSP_136) { 65061bfbdb8SLars-Peter Clausen tmp = readw(fifo_addr); 65161bfbdb8SLars-Peter Clausen for (i = 0; i < 4; ++i) { 65261bfbdb8SLars-Peter Clausen cmd->resp[i] = tmp << 24; 65361bfbdb8SLars-Peter Clausen tmp = readw(fifo_addr); 65461bfbdb8SLars-Peter Clausen cmd->resp[i] |= tmp << 8; 65561bfbdb8SLars-Peter Clausen tmp = readw(fifo_addr); 65661bfbdb8SLars-Peter Clausen cmd->resp[i] |= tmp >> 8; 65761bfbdb8SLars-Peter Clausen } 65861bfbdb8SLars-Peter Clausen } else { 65961bfbdb8SLars-Peter Clausen cmd->resp[0] = readw(fifo_addr) << 24; 66061bfbdb8SLars-Peter Clausen cmd->resp[0] |= readw(fifo_addr) << 8; 66161bfbdb8SLars-Peter Clausen cmd->resp[0] |= readw(fifo_addr) & 0xff; 66261bfbdb8SLars-Peter Clausen } 66361bfbdb8SLars-Peter Clausen } 66461bfbdb8SLars-Peter Clausen 66561bfbdb8SLars-Peter Clausen static void jz4740_mmc_send_command(struct jz4740_mmc_host *host, 66661bfbdb8SLars-Peter Clausen struct mmc_command *cmd) 66761bfbdb8SLars-Peter Clausen { 66861bfbdb8SLars-Peter Clausen uint32_t cmdat = host->cmdat; 66961bfbdb8SLars-Peter Clausen 67061bfbdb8SLars-Peter Clausen host->cmdat &= ~JZ_MMC_CMDAT_INIT; 67161bfbdb8SLars-Peter Clausen jz4740_mmc_clock_disable(host); 67261bfbdb8SLars-Peter Clausen 67361bfbdb8SLars-Peter Clausen host->cmd = cmd; 67461bfbdb8SLars-Peter Clausen 67561bfbdb8SLars-Peter Clausen if (cmd->flags & MMC_RSP_BUSY) 67661bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_BUSY; 67761bfbdb8SLars-Peter Clausen 67861bfbdb8SLars-Peter Clausen switch (mmc_resp_type(cmd)) { 67961bfbdb8SLars-Peter Clausen case MMC_RSP_R1B: 68061bfbdb8SLars-Peter Clausen case MMC_RSP_R1: 68161bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R1; 68261bfbdb8SLars-Peter Clausen break; 68361bfbdb8SLars-Peter Clausen case MMC_RSP_R2: 68461bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R2; 68561bfbdb8SLars-Peter Clausen break; 68661bfbdb8SLars-Peter Clausen case MMC_RSP_R3: 68761bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_RSP_R3; 68861bfbdb8SLars-Peter Clausen break; 68961bfbdb8SLars-Peter Clausen default: 69061bfbdb8SLars-Peter Clausen break; 69161bfbdb8SLars-Peter Clausen } 69261bfbdb8SLars-Peter Clausen 69361bfbdb8SLars-Peter Clausen if (cmd->data) { 69461bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_DATA_EN; 69561bfbdb8SLars-Peter Clausen if (cmd->data->flags & MMC_DATA_WRITE) 69661bfbdb8SLars-Peter Clausen cmdat |= JZ_MMC_CMDAT_WRITE; 6976a78768aSAlex Smith if (host->use_dma) { 6986a78768aSAlex Smith /* 6996a78768aSAlex Smith * The 4780's MMC controller has integrated DMA ability 7006a78768aSAlex Smith * in addition to being able to use the external DMA 7016a78768aSAlex Smith * controller. It moves DMA control bits to a separate 7026a78768aSAlex Smith * register. The DMA_SEL bit chooses the external 7036a78768aSAlex Smith * controller over the integrated one. Earlier SoCs 7046a78768aSAlex Smith * can only use the external controller, and have a 7056a78768aSAlex Smith * single DMA enable bit in CMDAT. 7066a78768aSAlex Smith */ 7076a78768aSAlex Smith if (host->version >= JZ_MMC_JZ4780) { 7086a78768aSAlex Smith writel(JZ_MMC_DMAC_DMA_EN | JZ_MMC_DMAC_DMA_SEL, 7096a78768aSAlex Smith host->base + JZ_REG_MMC_DMAC); 7106a78768aSAlex Smith } else { 7117ca27a6fSApelete Seketeli cmdat |= JZ_MMC_CMDAT_DMA_EN; 7126a78768aSAlex Smith } 7136a78768aSAlex Smith } else if (host->version >= JZ_MMC_JZ4780) { 7146a78768aSAlex Smith writel(0, host->base + JZ_REG_MMC_DMAC); 7156a78768aSAlex Smith } 71661bfbdb8SLars-Peter Clausen 71761bfbdb8SLars-Peter Clausen writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN); 71861bfbdb8SLars-Peter Clausen writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB); 71961bfbdb8SLars-Peter Clausen } 72061bfbdb8SLars-Peter Clausen 72161bfbdb8SLars-Peter Clausen writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD); 72261bfbdb8SLars-Peter Clausen writel(cmd->arg, host->base + JZ_REG_MMC_ARG); 72361bfbdb8SLars-Peter Clausen writel(cmdat, host->base + JZ_REG_MMC_CMDAT); 72461bfbdb8SLars-Peter Clausen 72561bfbdb8SLars-Peter Clausen jz4740_mmc_clock_enable(host, 1); 72661bfbdb8SLars-Peter Clausen } 72761bfbdb8SLars-Peter Clausen 72861bfbdb8SLars-Peter Clausen static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host) 72961bfbdb8SLars-Peter Clausen { 73061bfbdb8SLars-Peter Clausen struct mmc_command *cmd = host->req->cmd; 73161bfbdb8SLars-Peter Clausen struct mmc_data *data = cmd->data; 73261bfbdb8SLars-Peter Clausen int direction; 73361bfbdb8SLars-Peter Clausen 73461bfbdb8SLars-Peter Clausen if (data->flags & MMC_DATA_READ) 73561bfbdb8SLars-Peter Clausen direction = SG_MITER_TO_SG; 73661bfbdb8SLars-Peter Clausen else 73761bfbdb8SLars-Peter Clausen direction = SG_MITER_FROM_SG; 73861bfbdb8SLars-Peter Clausen 73961bfbdb8SLars-Peter Clausen sg_miter_start(&host->miter, data->sg, data->sg_len, direction); 74061bfbdb8SLars-Peter Clausen } 74161bfbdb8SLars-Peter Clausen 74261bfbdb8SLars-Peter Clausen 74361bfbdb8SLars-Peter Clausen static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) 74461bfbdb8SLars-Peter Clausen { 74561bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid; 74661bfbdb8SLars-Peter Clausen struct mmc_command *cmd = host->req->cmd; 74761bfbdb8SLars-Peter Clausen struct mmc_request *req = host->req; 7487ca27a6fSApelete Seketeli struct mmc_data *data = cmd->data; 74961bfbdb8SLars-Peter Clausen bool timeout = false; 75061bfbdb8SLars-Peter Clausen 75161bfbdb8SLars-Peter Clausen if (cmd->error) 75261bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_DONE; 75361bfbdb8SLars-Peter Clausen 75461bfbdb8SLars-Peter Clausen switch (host->state) { 75561bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_READ_RESPONSE: 75661bfbdb8SLars-Peter Clausen if (cmd->flags & MMC_RSP_PRESENT) 75761bfbdb8SLars-Peter Clausen jz4740_mmc_read_response(host, cmd); 75861bfbdb8SLars-Peter Clausen 7597ca27a6fSApelete Seketeli if (!data) 76061bfbdb8SLars-Peter Clausen break; 76161bfbdb8SLars-Peter Clausen 76261bfbdb8SLars-Peter Clausen jz_mmc_prepare_data_transfer(host); 76361bfbdb8SLars-Peter Clausen 76461bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_TRANSFER_DATA: 7657ca27a6fSApelete Seketeli if (host->use_dma) { 766bb2f4592SApelete Seketeli /* Use DMA if enabled. 767bb2f4592SApelete Seketeli * Data transfer direction is defined later by 768bb2f4592SApelete Seketeli * relying on data flags in 769bb2f4592SApelete Seketeli * jz4740_mmc_prepare_dma_data() and 770bb2f4592SApelete Seketeli * jz4740_mmc_start_dma_transfer(). 7717ca27a6fSApelete Seketeli */ 7727ca27a6fSApelete Seketeli timeout = jz4740_mmc_start_dma_transfer(host, data); 7737ca27a6fSApelete Seketeli data->bytes_xfered = data->blocks * data->blksz; 7747ca27a6fSApelete Seketeli } else if (data->flags & MMC_DATA_READ) 775bb2f4592SApelete Seketeli /* Use PIO if DMA is not enabled. 776bb2f4592SApelete Seketeli * Data transfer direction was defined before 777bb2f4592SApelete Seketeli * by relying on data flags in 778bb2f4592SApelete Seketeli * jz_mmc_prepare_data_transfer(). 7797ca27a6fSApelete Seketeli */ 7807ca27a6fSApelete Seketeli timeout = jz4740_mmc_read_data(host, data); 78161bfbdb8SLars-Peter Clausen else 7827ca27a6fSApelete Seketeli timeout = jz4740_mmc_write_data(host, data); 78361bfbdb8SLars-Peter Clausen 78461bfbdb8SLars-Peter Clausen if (unlikely(timeout)) { 78561bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_TRANSFER_DATA; 78661bfbdb8SLars-Peter Clausen break; 78761bfbdb8SLars-Peter Clausen } 78861bfbdb8SLars-Peter Clausen 7897ca27a6fSApelete Seketeli jz4740_mmc_transfer_check_state(host, data); 79061bfbdb8SLars-Peter Clausen 79161bfbdb8SLars-Peter Clausen timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE); 79261bfbdb8SLars-Peter Clausen if (unlikely(timeout)) { 79361bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_SEND_STOP; 79461bfbdb8SLars-Peter Clausen break; 79561bfbdb8SLars-Peter Clausen } 7966a78768aSAlex Smith jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_DATA_TRAN_DONE); 79761bfbdb8SLars-Peter Clausen 79861bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_SEND_STOP: 79961bfbdb8SLars-Peter Clausen if (!req->stop) 80061bfbdb8SLars-Peter Clausen break; 80161bfbdb8SLars-Peter Clausen 80261bfbdb8SLars-Peter Clausen jz4740_mmc_send_command(host, req->stop); 80361bfbdb8SLars-Peter Clausen 8041acee84bSAlex Smith if (mmc_resp_type(req->stop) & MMC_RSP_BUSY) { 8051acee84bSAlex Smith timeout = jz4740_mmc_poll_irq(host, 8061acee84bSAlex Smith JZ_MMC_IRQ_PRG_DONE); 80761bfbdb8SLars-Peter Clausen if (timeout) { 80861bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_DONE; 80961bfbdb8SLars-Peter Clausen break; 81061bfbdb8SLars-Peter Clausen } 8111acee84bSAlex Smith } 81261bfbdb8SLars-Peter Clausen case JZ4740_MMC_STATE_DONE: 81361bfbdb8SLars-Peter Clausen break; 81461bfbdb8SLars-Peter Clausen } 81561bfbdb8SLars-Peter Clausen 81661bfbdb8SLars-Peter Clausen if (!timeout) 81761bfbdb8SLars-Peter Clausen jz4740_mmc_request_done(host); 81861bfbdb8SLars-Peter Clausen 81961bfbdb8SLars-Peter Clausen return IRQ_HANDLED; 82061bfbdb8SLars-Peter Clausen } 82161bfbdb8SLars-Peter Clausen 82261bfbdb8SLars-Peter Clausen static irqreturn_t jz_mmc_irq(int irq, void *devid) 82361bfbdb8SLars-Peter Clausen { 82461bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = devid; 82561bfbdb8SLars-Peter Clausen struct mmc_command *cmd = host->cmd; 8266a78768aSAlex Smith uint32_t irq_reg, status, tmp; 82761bfbdb8SLars-Peter Clausen 8286a78768aSAlex Smith status = readl(host->base + JZ_REG_MMC_STATUS); 8296a78768aSAlex Smith irq_reg = jz4740_mmc_read_irq_reg(host); 83061bfbdb8SLars-Peter Clausen 83161bfbdb8SLars-Peter Clausen tmp = irq_reg; 83261bfbdb8SLars-Peter Clausen irq_reg &= ~host->irq_mask; 83361bfbdb8SLars-Peter Clausen 83461bfbdb8SLars-Peter Clausen tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ | 83561bfbdb8SLars-Peter Clausen JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); 83661bfbdb8SLars-Peter Clausen 83761bfbdb8SLars-Peter Clausen if (tmp != irq_reg) 8386a78768aSAlex Smith jz4740_mmc_write_irq_reg(host, tmp & ~irq_reg); 83961bfbdb8SLars-Peter Clausen 84061bfbdb8SLars-Peter Clausen if (irq_reg & JZ_MMC_IRQ_SDIO) { 8416a78768aSAlex Smith jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_SDIO); 84261bfbdb8SLars-Peter Clausen mmc_signal_sdio_irq(host->mmc); 84361bfbdb8SLars-Peter Clausen irq_reg &= ~JZ_MMC_IRQ_SDIO; 84461bfbdb8SLars-Peter Clausen } 84561bfbdb8SLars-Peter Clausen 84661bfbdb8SLars-Peter Clausen if (host->req && cmd && irq_reg) { 84761bfbdb8SLars-Peter Clausen if (test_and_clear_bit(0, &host->waiting)) { 84861bfbdb8SLars-Peter Clausen del_timer(&host->timeout_timer); 84961bfbdb8SLars-Peter Clausen 85061bfbdb8SLars-Peter Clausen if (status & JZ_MMC_STATUS_TIMEOUT_RES) { 85161bfbdb8SLars-Peter Clausen cmd->error = -ETIMEDOUT; 85261bfbdb8SLars-Peter Clausen } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { 85361bfbdb8SLars-Peter Clausen cmd->error = -EIO; 85461bfbdb8SLars-Peter Clausen } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | 85561bfbdb8SLars-Peter Clausen JZ_MMC_STATUS_CRC_WRITE_ERROR)) { 85661bfbdb8SLars-Peter Clausen if (cmd->data) 85761bfbdb8SLars-Peter Clausen cmd->data->error = -EIO; 85861bfbdb8SLars-Peter Clausen cmd->error = -EIO; 85961bfbdb8SLars-Peter Clausen } 86061bfbdb8SLars-Peter Clausen 86161bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, irq_reg, false); 8626a78768aSAlex Smith jz4740_mmc_write_irq_reg(host, irq_reg); 86361bfbdb8SLars-Peter Clausen 86461bfbdb8SLars-Peter Clausen return IRQ_WAKE_THREAD; 86561bfbdb8SLars-Peter Clausen } 86661bfbdb8SLars-Peter Clausen } 86761bfbdb8SLars-Peter Clausen 86861bfbdb8SLars-Peter Clausen return IRQ_HANDLED; 86961bfbdb8SLars-Peter Clausen } 87061bfbdb8SLars-Peter Clausen 87161bfbdb8SLars-Peter Clausen static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) 87261bfbdb8SLars-Peter Clausen { 87361bfbdb8SLars-Peter Clausen int div = 0; 87461bfbdb8SLars-Peter Clausen int real_rate; 87561bfbdb8SLars-Peter Clausen 87661bfbdb8SLars-Peter Clausen jz4740_mmc_clock_disable(host); 8776861fce6SAlex Smith clk_set_rate(host->clk, host->mmc->f_max); 87861bfbdb8SLars-Peter Clausen 87961bfbdb8SLars-Peter Clausen real_rate = clk_get_rate(host->clk); 88061bfbdb8SLars-Peter Clausen 88161bfbdb8SLars-Peter Clausen while (real_rate > rate && div < 7) { 88261bfbdb8SLars-Peter Clausen ++div; 88361bfbdb8SLars-Peter Clausen real_rate >>= 1; 88461bfbdb8SLars-Peter Clausen } 88561bfbdb8SLars-Peter Clausen 88661bfbdb8SLars-Peter Clausen writew(div, host->base + JZ_REG_MMC_CLKRT); 88761bfbdb8SLars-Peter Clausen return real_rate; 88861bfbdb8SLars-Peter Clausen } 88961bfbdb8SLars-Peter Clausen 89061bfbdb8SLars-Peter Clausen static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) 89161bfbdb8SLars-Peter Clausen { 89261bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 89361bfbdb8SLars-Peter Clausen 89461bfbdb8SLars-Peter Clausen host->req = req; 89561bfbdb8SLars-Peter Clausen 8966a78768aSAlex Smith jz4740_mmc_write_irq_reg(host, ~0); 89761bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true); 89861bfbdb8SLars-Peter Clausen 89961bfbdb8SLars-Peter Clausen host->state = JZ4740_MMC_STATE_READ_RESPONSE; 90061bfbdb8SLars-Peter Clausen set_bit(0, &host->waiting); 90161bfbdb8SLars-Peter Clausen mod_timer(&host->timeout_timer, jiffies + 5*HZ); 90261bfbdb8SLars-Peter Clausen jz4740_mmc_send_command(host, req->cmd); 90361bfbdb8SLars-Peter Clausen } 90461bfbdb8SLars-Peter Clausen 90561bfbdb8SLars-Peter Clausen static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 90661bfbdb8SLars-Peter Clausen { 90761bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 90861bfbdb8SLars-Peter Clausen if (ios->clock) 90961bfbdb8SLars-Peter Clausen jz4740_mmc_set_clock_rate(host, ios->clock); 91061bfbdb8SLars-Peter Clausen 91161bfbdb8SLars-Peter Clausen switch (ios->power_mode) { 91261bfbdb8SLars-Peter Clausen case MMC_POWER_UP: 91361bfbdb8SLars-Peter Clausen jz4740_mmc_reset(host); 91461e11ebaSEzequiel Garcia if (host->pdata && gpio_is_valid(host->pdata->gpio_power)) 91561bfbdb8SLars-Peter Clausen gpio_set_value(host->pdata->gpio_power, 91661bfbdb8SLars-Peter Clausen !host->pdata->power_active_low); 91761bfbdb8SLars-Peter Clausen host->cmdat |= JZ_MMC_CMDAT_INIT; 918fca9661cSLars-Peter Clausen clk_prepare_enable(host->clk); 91961bfbdb8SLars-Peter Clausen break; 92061bfbdb8SLars-Peter Clausen case MMC_POWER_ON: 92161bfbdb8SLars-Peter Clausen break; 92261bfbdb8SLars-Peter Clausen default: 92361e11ebaSEzequiel Garcia if (host->pdata && gpio_is_valid(host->pdata->gpio_power)) 92461bfbdb8SLars-Peter Clausen gpio_set_value(host->pdata->gpio_power, 92561bfbdb8SLars-Peter Clausen host->pdata->power_active_low); 926fca9661cSLars-Peter Clausen clk_disable_unprepare(host->clk); 92761bfbdb8SLars-Peter Clausen break; 92861bfbdb8SLars-Peter Clausen } 92961bfbdb8SLars-Peter Clausen 93061bfbdb8SLars-Peter Clausen switch (ios->bus_width) { 93161bfbdb8SLars-Peter Clausen case MMC_BUS_WIDTH_1: 93261bfbdb8SLars-Peter Clausen host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT; 93361bfbdb8SLars-Peter Clausen break; 93461bfbdb8SLars-Peter Clausen case MMC_BUS_WIDTH_4: 93561bfbdb8SLars-Peter Clausen host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT; 93661bfbdb8SLars-Peter Clausen break; 93761bfbdb8SLars-Peter Clausen default: 93861bfbdb8SLars-Peter Clausen break; 93961bfbdb8SLars-Peter Clausen } 94061bfbdb8SLars-Peter Clausen } 94161bfbdb8SLars-Peter Clausen 94261bfbdb8SLars-Peter Clausen static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) 94361bfbdb8SLars-Peter Clausen { 94461bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = mmc_priv(mmc); 94561bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable); 94661bfbdb8SLars-Peter Clausen } 94761bfbdb8SLars-Peter Clausen 94861bfbdb8SLars-Peter Clausen static const struct mmc_host_ops jz4740_mmc_ops = { 94961bfbdb8SLars-Peter Clausen .request = jz4740_mmc_request, 950bb2f4592SApelete Seketeli .pre_req = jz4740_mmc_pre_request, 951bb2f4592SApelete Seketeli .post_req = jz4740_mmc_post_request, 95261bfbdb8SLars-Peter Clausen .set_ios = jz4740_mmc_set_ios, 95358e300afSLars-Peter Clausen .get_ro = mmc_gpio_get_ro, 95458e300afSLars-Peter Clausen .get_cd = mmc_gpio_get_cd, 95561bfbdb8SLars-Peter Clausen .enable_sdio_irq = jz4740_mmc_enable_sdio_irq, 95661bfbdb8SLars-Peter Clausen }; 95761bfbdb8SLars-Peter Clausen 958c3be1efdSBill Pemberton static int jz4740_mmc_request_gpio(struct device *dev, int gpio, 95961bfbdb8SLars-Peter Clausen const char *name, bool output, int value) 96061bfbdb8SLars-Peter Clausen { 96161bfbdb8SLars-Peter Clausen int ret; 96261bfbdb8SLars-Peter Clausen 96361bfbdb8SLars-Peter Clausen if (!gpio_is_valid(gpio)) 96461bfbdb8SLars-Peter Clausen return 0; 96561bfbdb8SLars-Peter Clausen 96661bfbdb8SLars-Peter Clausen ret = gpio_request(gpio, name); 96761bfbdb8SLars-Peter Clausen if (ret) { 96861bfbdb8SLars-Peter Clausen dev_err(dev, "Failed to request %s gpio: %d\n", name, ret); 96961bfbdb8SLars-Peter Clausen return ret; 97061bfbdb8SLars-Peter Clausen } 97161bfbdb8SLars-Peter Clausen 97261bfbdb8SLars-Peter Clausen if (output) 97361bfbdb8SLars-Peter Clausen gpio_direction_output(gpio, value); 97461bfbdb8SLars-Peter Clausen else 97561bfbdb8SLars-Peter Clausen gpio_direction_input(gpio); 97661bfbdb8SLars-Peter Clausen 97761bfbdb8SLars-Peter Clausen return 0; 97861bfbdb8SLars-Peter Clausen } 97961bfbdb8SLars-Peter Clausen 98058e300afSLars-Peter Clausen static int jz4740_mmc_request_gpios(struct mmc_host *mmc, 98158e300afSLars-Peter Clausen struct platform_device *pdev) 98261bfbdb8SLars-Peter Clausen { 98339e9ef1dSEzequiel Garcia struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev); 98458e300afSLars-Peter Clausen int ret = 0; 98561bfbdb8SLars-Peter Clausen 98661bfbdb8SLars-Peter Clausen if (!pdata) 98761bfbdb8SLars-Peter Clausen return 0; 98861bfbdb8SLars-Peter Clausen 98958e300afSLars-Peter Clausen if (!pdata->card_detect_active_low) 99058e300afSLars-Peter Clausen mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; 99158e300afSLars-Peter Clausen if (!pdata->read_only_active_low) 99258e300afSLars-Peter Clausen mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; 99358e300afSLars-Peter Clausen 99458e300afSLars-Peter Clausen if (gpio_is_valid(pdata->gpio_card_detect)) { 995214fc309SLaurent Pinchart ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0); 99661bfbdb8SLars-Peter Clausen if (ret) 99761bfbdb8SLars-Peter Clausen return ret; 99861bfbdb8SLars-Peter Clausen } 99961bfbdb8SLars-Peter Clausen 100058e300afSLars-Peter Clausen if (gpio_is_valid(pdata->gpio_read_only)) { 100158e300afSLars-Peter Clausen ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only); 100258e300afSLars-Peter Clausen if (ret) 100358e300afSLars-Peter Clausen return ret; 100461bfbdb8SLars-Peter Clausen } 100561bfbdb8SLars-Peter Clausen 100658e300afSLars-Peter Clausen return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power, 100758e300afSLars-Peter Clausen "MMC read only", true, pdata->power_active_low); 100861bfbdb8SLars-Peter Clausen } 100961bfbdb8SLars-Peter Clausen 101061bfbdb8SLars-Peter Clausen static void jz4740_mmc_free_gpios(struct platform_device *pdev) 101161bfbdb8SLars-Peter Clausen { 101239e9ef1dSEzequiel Garcia struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev); 101361bfbdb8SLars-Peter Clausen 101461bfbdb8SLars-Peter Clausen if (!pdata) 101561bfbdb8SLars-Peter Clausen return; 101661bfbdb8SLars-Peter Clausen 101761bfbdb8SLars-Peter Clausen if (gpio_is_valid(pdata->gpio_power)) 101861bfbdb8SLars-Peter Clausen gpio_free(pdata->gpio_power); 101961bfbdb8SLars-Peter Clausen } 102061bfbdb8SLars-Peter Clausen 102161e11ebaSEzequiel Garcia static const struct of_device_id jz4740_mmc_of_match[] = { 102261e11ebaSEzequiel Garcia { .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 }, 10236a78768aSAlex Smith { .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 }, 102461e11ebaSEzequiel Garcia {}, 102561e11ebaSEzequiel Garcia }; 102661e11ebaSEzequiel Garcia MODULE_DEVICE_TABLE(of, jz4740_mmc_of_match); 102761e11ebaSEzequiel Garcia 1028c3be1efdSBill Pemberton static int jz4740_mmc_probe(struct platform_device* pdev) 102961bfbdb8SLars-Peter Clausen { 103061bfbdb8SLars-Peter Clausen int ret; 103161bfbdb8SLars-Peter Clausen struct mmc_host *mmc; 103261bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host; 103361e11ebaSEzequiel Garcia const struct of_device_id *match; 103461bfbdb8SLars-Peter Clausen struct jz4740_mmc_platform_data *pdata; 103561bfbdb8SLars-Peter Clausen 103639e9ef1dSEzequiel Garcia pdata = dev_get_platdata(&pdev->dev); 103761bfbdb8SLars-Peter Clausen 103861bfbdb8SLars-Peter Clausen mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); 103961bfbdb8SLars-Peter Clausen if (!mmc) { 104061bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to alloc mmc host structure\n"); 104161bfbdb8SLars-Peter Clausen return -ENOMEM; 104261bfbdb8SLars-Peter Clausen } 104361bfbdb8SLars-Peter Clausen 104461bfbdb8SLars-Peter Clausen host = mmc_priv(mmc); 104561bfbdb8SLars-Peter Clausen host->pdata = pdata; 104661bfbdb8SLars-Peter Clausen 104761e11ebaSEzequiel Garcia match = of_match_device(jz4740_mmc_of_match, &pdev->dev); 104861e11ebaSEzequiel Garcia if (match) { 104961e11ebaSEzequiel Garcia host->version = (enum jz4740_mmc_version)match->data; 105061e11ebaSEzequiel Garcia ret = mmc_of_parse(mmc); 105161e11ebaSEzequiel Garcia if (ret) { 105261e11ebaSEzequiel Garcia if (ret != -EPROBE_DEFER) 105361e11ebaSEzequiel Garcia dev_err(&pdev->dev, 105461e11ebaSEzequiel Garcia "could not parse of data: %d\n", ret); 105561e11ebaSEzequiel Garcia goto err_free_host; 105661e11ebaSEzequiel Garcia } 105761e11ebaSEzequiel Garcia } else { 105861e11ebaSEzequiel Garcia /* JZ4740 should be the only one using legacy probe */ 105961e11ebaSEzequiel Garcia host->version = JZ_MMC_JZ4740; 106061e11ebaSEzequiel Garcia mmc->caps |= MMC_CAP_SDIO_IRQ; 106161e11ebaSEzequiel Garcia if (!(pdata && pdata->data_1bit)) 106261e11ebaSEzequiel Garcia mmc->caps |= MMC_CAP_4_BIT_DATA; 106361e11ebaSEzequiel Garcia ret = jz4740_mmc_request_gpios(mmc, pdev); 106461e11ebaSEzequiel Garcia if (ret) 106561e11ebaSEzequiel Garcia goto err_free_host; 106661e11ebaSEzequiel Garcia } 106761e11ebaSEzequiel Garcia 106861bfbdb8SLars-Peter Clausen host->irq = platform_get_irq(pdev, 0); 106961bfbdb8SLars-Peter Clausen if (host->irq < 0) { 107061bfbdb8SLars-Peter Clausen ret = host->irq; 107161bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); 107261bfbdb8SLars-Peter Clausen goto err_free_host; 107361bfbdb8SLars-Peter Clausen } 107461bfbdb8SLars-Peter Clausen 1075017d84bdSLars-Peter Clausen host->clk = devm_clk_get(&pdev->dev, "mmc"); 10763119cbdaSJamie Iles if (IS_ERR(host->clk)) { 10773119cbdaSJamie Iles ret = PTR_ERR(host->clk); 107861bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to get mmc clock\n"); 107961bfbdb8SLars-Peter Clausen goto err_free_host; 108061bfbdb8SLars-Peter Clausen } 108161bfbdb8SLars-Peter Clausen 10827ca27a6fSApelete Seketeli host->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10837ca27a6fSApelete Seketeli host->base = devm_ioremap_resource(&pdev->dev, host->mem_res); 10843e7e8c18SWei Yongjun if (IS_ERR(host->base)) { 10853e7e8c18SWei Yongjun ret = PTR_ERR(host->base); 10867ca27a6fSApelete Seketeli dev_err(&pdev->dev, "Failed to ioremap base memory\n"); 1087017d84bdSLars-Peter Clausen goto err_free_host; 108861bfbdb8SLars-Peter Clausen } 108961bfbdb8SLars-Peter Clausen 109061bfbdb8SLars-Peter Clausen mmc->ops = &jz4740_mmc_ops; 109161e11ebaSEzequiel Garcia if (!mmc->f_max) 109261bfbdb8SLars-Peter Clausen mmc->f_max = JZ_MMC_CLK_RATE; 109361e11ebaSEzequiel Garcia mmc->f_min = mmc->f_max / 128; 109461bfbdb8SLars-Peter Clausen mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 109561bfbdb8SLars-Peter Clausen 109661bfbdb8SLars-Peter Clausen mmc->max_blk_size = (1 << 10) - 1; 109761bfbdb8SLars-Peter Clausen mmc->max_blk_count = (1 << 15) - 1; 109861bfbdb8SLars-Peter Clausen mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 109961bfbdb8SLars-Peter Clausen 1100a36274e0SMartin K. Petersen mmc->max_segs = 128; 110161bfbdb8SLars-Peter Clausen mmc->max_seg_size = mmc->max_req_size; 110261bfbdb8SLars-Peter Clausen 110361bfbdb8SLars-Peter Clausen host->mmc = mmc; 110461bfbdb8SLars-Peter Clausen host->pdev = pdev; 110561bfbdb8SLars-Peter Clausen spin_lock_init(&host->lock); 11066a78768aSAlex Smith host->irq_mask = ~0; 110761bfbdb8SLars-Peter Clausen 1108436a3cfdSZubair Lutfullah Kakakhel jz4740_mmc_reset(host); 1109436a3cfdSZubair Lutfullah Kakakhel 111061bfbdb8SLars-Peter Clausen ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, 111161bfbdb8SLars-Peter Clausen dev_name(&pdev->dev), host); 111261bfbdb8SLars-Peter Clausen if (ret) { 111361bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); 111458e300afSLars-Peter Clausen goto err_free_gpios; 111561bfbdb8SLars-Peter Clausen } 111661bfbdb8SLars-Peter Clausen 111761bfbdb8SLars-Peter Clausen jz4740_mmc_clock_disable(host); 11182ee4f620SKees Cook timer_setup(&host->timeout_timer, jz4740_mmc_timeout, 0); 111961bfbdb8SLars-Peter Clausen 11207e8466e2SPaul Cercueil ret = jz4740_mmc_acquire_dma_channels(host); 11217e8466e2SPaul Cercueil if (ret == -EPROBE_DEFER) 11227e8466e2SPaul Cercueil goto err_free_irq; 11237e8466e2SPaul Cercueil host->use_dma = !ret; 11247ca27a6fSApelete Seketeli 112561bfbdb8SLars-Peter Clausen platform_set_drvdata(pdev, host); 112661bfbdb8SLars-Peter Clausen ret = mmc_add_host(mmc); 112761bfbdb8SLars-Peter Clausen 112861bfbdb8SLars-Peter Clausen if (ret) { 112961bfbdb8SLars-Peter Clausen dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret); 11307e8466e2SPaul Cercueil goto err_release_dma; 113161bfbdb8SLars-Peter Clausen } 113261bfbdb8SLars-Peter Clausen dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); 113361bfbdb8SLars-Peter Clausen 11347ca27a6fSApelete Seketeli dev_info(&pdev->dev, "Using %s, %d-bit mode\n", 11357ca27a6fSApelete Seketeli host->use_dma ? "DMA" : "PIO", 11367ca27a6fSApelete Seketeli (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1); 11377ca27a6fSApelete Seketeli 113861bfbdb8SLars-Peter Clausen return 0; 113961bfbdb8SLars-Peter Clausen 11407e8466e2SPaul Cercueil err_release_dma: 11417e8466e2SPaul Cercueil if (host->use_dma) 11427e8466e2SPaul Cercueil jz4740_mmc_release_dma_channels(host); 114361bfbdb8SLars-Peter Clausen err_free_irq: 114461bfbdb8SLars-Peter Clausen free_irq(host->irq, host); 114561bfbdb8SLars-Peter Clausen err_free_gpios: 114661bfbdb8SLars-Peter Clausen jz4740_mmc_free_gpios(pdev); 114761bfbdb8SLars-Peter Clausen err_free_host: 114861bfbdb8SLars-Peter Clausen mmc_free_host(mmc); 114961bfbdb8SLars-Peter Clausen 115061bfbdb8SLars-Peter Clausen return ret; 115161bfbdb8SLars-Peter Clausen } 115261bfbdb8SLars-Peter Clausen 11536e0ee714SBill Pemberton static int jz4740_mmc_remove(struct platform_device *pdev) 115461bfbdb8SLars-Peter Clausen { 115561bfbdb8SLars-Peter Clausen struct jz4740_mmc_host *host = platform_get_drvdata(pdev); 115661bfbdb8SLars-Peter Clausen 115761bfbdb8SLars-Peter Clausen del_timer_sync(&host->timeout_timer); 115861bfbdb8SLars-Peter Clausen jz4740_mmc_set_irq_enabled(host, 0xff, false); 115961bfbdb8SLars-Peter Clausen jz4740_mmc_reset(host); 116061bfbdb8SLars-Peter Clausen 116161bfbdb8SLars-Peter Clausen mmc_remove_host(host->mmc); 116261bfbdb8SLars-Peter Clausen 116361bfbdb8SLars-Peter Clausen free_irq(host->irq, host); 116461bfbdb8SLars-Peter Clausen 116561bfbdb8SLars-Peter Clausen jz4740_mmc_free_gpios(pdev); 116661bfbdb8SLars-Peter Clausen 11677ca27a6fSApelete Seketeli if (host->use_dma) 11687ca27a6fSApelete Seketeli jz4740_mmc_release_dma_channels(host); 11697ca27a6fSApelete Seketeli 117061bfbdb8SLars-Peter Clausen mmc_free_host(host->mmc); 117161bfbdb8SLars-Peter Clausen 117261bfbdb8SLars-Peter Clausen return 0; 117361bfbdb8SLars-Peter Clausen } 117461bfbdb8SLars-Peter Clausen 11755d5c0350SLars-Peter Clausen #ifdef CONFIG_PM_SLEEP 117661bfbdb8SLars-Peter Clausen 117761bfbdb8SLars-Peter Clausen static int jz4740_mmc_suspend(struct device *dev) 117861bfbdb8SLars-Peter Clausen { 1179fa5ed6bcSPaul Cercueil return pinctrl_pm_select_sleep_state(dev); 118061bfbdb8SLars-Peter Clausen } 118161bfbdb8SLars-Peter Clausen 118261bfbdb8SLars-Peter Clausen static int jz4740_mmc_resume(struct device *dev) 118361bfbdb8SLars-Peter Clausen { 1184fa5ed6bcSPaul Cercueil return pinctrl_pm_select_default_state(dev); 118561bfbdb8SLars-Peter Clausen } 118661bfbdb8SLars-Peter Clausen 11875d5c0350SLars-Peter Clausen static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, 11885d5c0350SLars-Peter Clausen jz4740_mmc_resume); 118961bfbdb8SLars-Peter Clausen #define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops) 119061bfbdb8SLars-Peter Clausen #else 119161bfbdb8SLars-Peter Clausen #define JZ4740_MMC_PM_OPS NULL 119261bfbdb8SLars-Peter Clausen #endif 119361bfbdb8SLars-Peter Clausen 119461bfbdb8SLars-Peter Clausen static struct platform_driver jz4740_mmc_driver = { 119561bfbdb8SLars-Peter Clausen .probe = jz4740_mmc_probe, 11960433c143SBill Pemberton .remove = jz4740_mmc_remove, 119761bfbdb8SLars-Peter Clausen .driver = { 119861bfbdb8SLars-Peter Clausen .name = "jz4740-mmc", 119961e11ebaSEzequiel Garcia .of_match_table = of_match_ptr(jz4740_mmc_of_match), 120061bfbdb8SLars-Peter Clausen .pm = JZ4740_MMC_PM_OPS, 120161bfbdb8SLars-Peter Clausen }, 120261bfbdb8SLars-Peter Clausen }; 120361bfbdb8SLars-Peter Clausen 1204d1f81a64SAxel Lin module_platform_driver(jz4740_mmc_driver); 120561bfbdb8SLars-Peter Clausen 120661bfbdb8SLars-Peter Clausen MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); 120761bfbdb8SLars-Peter Clausen MODULE_LICENSE("GPL"); 120861bfbdb8SLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1209