1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21c6a0718SPierre Ossman /* 370f10482SPierre Ossman * linux/drivers/mmc/host/pxa.c - PXA MMCI driver 41c6a0718SPierre Ossman * 51c6a0718SPierre Ossman * Copyright (C) 2003 Russell King, All Rights Reserved. 61c6a0718SPierre Ossman * 71c6a0718SPierre Ossman * This hardware is really sick: 81c6a0718SPierre Ossman * - No way to clear interrupts. 91c6a0718SPierre Ossman * - Have to turn off the clock whenever we touch the device. 101c6a0718SPierre Ossman * - Doesn't tell you how many data blocks were transferred. 111c6a0718SPierre Ossman * Yuck! 121c6a0718SPierre Ossman * 131c6a0718SPierre Ossman * 1 and 3 byte data transfers not supported 141c6a0718SPierre Ossman * max block length up to 1023 151c6a0718SPierre Ossman */ 161c6a0718SPierre Ossman #include <linux/module.h> 171c6a0718SPierre Ossman #include <linux/init.h> 181c6a0718SPierre Ossman #include <linux/ioport.h> 191c6a0718SPierre Ossman #include <linux/platform_device.h> 201c6a0718SPierre Ossman #include <linux/delay.h> 211c6a0718SPierre Ossman #include <linux/interrupt.h> 226464b714SDaniel Mack #include <linux/dmaengine.h> 231c6a0718SPierre Ossman #include <linux/dma-mapping.h> 24ebebd9b0SRussell King #include <linux/clk.h> 25ebebd9b0SRussell King #include <linux/err.h> 261c6a0718SPierre Ossman #include <linux/mmc/host.h> 27fd546ee6SRobert Jarzmik #include <linux/mmc/slot-gpio.h> 2805678a96SRussell King #include <linux/io.h> 298385f9cbSDaniel Ribeiro #include <linux/regulator/consumer.h> 30f54005b5SLinus Walleij #include <linux/gpio/consumer.h> 315a0e3ad6STejun Heo #include <linux/gfp.h> 32e6027b46SDaniel Mack #include <linux/of.h> 33e6027b46SDaniel Mack #include <linux/of_device.h> 3408d3df8cSArnd Bergmann #include <linux/soc/pxa/cpu.h> 351c6a0718SPierre Ossman 3687dfb311SMasahiro Yamada #include <linux/sizes.h> 371c6a0718SPierre Ossman 38293b2da1SArnd Bergmann #include <linux/platform_data/mmc-pxamci.h> 391c6a0718SPierre Ossman 401c6a0718SPierre Ossman #include "pxamci.h" 411c6a0718SPierre Ossman 421c6a0718SPierre Ossman #define DRIVER_NAME "pxa2xx-mci" 431c6a0718SPierre Ossman 441c6a0718SPierre Ossman #define NR_SG 1 45d8cb70d1SRussell King #define CLKRT_OFF (~0) 461c6a0718SPierre Ossman 47fa3f9938SHaojian Zhuang #define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310() \ 48fa3f9938SHaojian Zhuang || cpu_is_pxa935()) 49fa3f9938SHaojian Zhuang 501c6a0718SPierre Ossman struct pxamci_host { 511c6a0718SPierre Ossman struct mmc_host *mmc; 521c6a0718SPierre Ossman spinlock_t lock; 531c6a0718SPierre Ossman struct resource *res; 541c6a0718SPierre Ossman void __iomem *base; 55ebebd9b0SRussell King struct clk *clk; 56ebebd9b0SRussell King unsigned long clkrate; 571c6a0718SPierre Ossman unsigned int clkrt; 581c6a0718SPierre Ossman unsigned int cmdat; 591c6a0718SPierre Ossman unsigned int imask; 601c6a0718SPierre Ossman unsigned int power_mode; 6138a8dda9SDaniel Mack unsigned long detect_delay_ms; 62c914a27cSLinus Walleij bool use_ro_gpio; 63f54005b5SLinus Walleij struct gpio_desc *power; 641c6a0718SPierre Ossman struct pxamci_platform_data *pdata; 651c6a0718SPierre Ossman 661c6a0718SPierre Ossman struct mmc_request *mrq; 671c6a0718SPierre Ossman struct mmc_command *cmd; 681c6a0718SPierre Ossman struct mmc_data *data; 691c6a0718SPierre Ossman 706464b714SDaniel Mack struct dma_chan *dma_chan_rx; 716464b714SDaniel Mack struct dma_chan *dma_chan_tx; 726464b714SDaniel Mack dma_cookie_t dma_cookie; 731c6a0718SPierre Ossman unsigned int dma_len; 741c6a0718SPierre Ossman unsigned int dma_dir; 751c6a0718SPierre Ossman }; 761c6a0718SPierre Ossman 7761951fd6SDaniel Mack static int pxamci_init_ocr(struct pxamci_host *host) 788385f9cbSDaniel Ribeiro { 7961951fd6SDaniel Mack struct mmc_host *mmc = host->mmc; 8061951fd6SDaniel Mack int ret; 818385f9cbSDaniel Ribeiro 8261951fd6SDaniel Mack ret = mmc_regulator_get_supply(mmc); 8361951fd6SDaniel Mack if (ret < 0) 8461951fd6SDaniel Mack return ret; 8561951fd6SDaniel Mack 8661951fd6SDaniel Mack if (IS_ERR(mmc->supply.vmmc)) { 878385f9cbSDaniel Ribeiro /* fall-back to platform data */ 8861951fd6SDaniel Mack mmc->ocr_avail = host->pdata ? 898385f9cbSDaniel Ribeiro host->pdata->ocr_mask : 908385f9cbSDaniel Ribeiro MMC_VDD_32_33 | MMC_VDD_33_34; 918385f9cbSDaniel Ribeiro } 9261951fd6SDaniel Mack 9361951fd6SDaniel Mack return 0; 948385f9cbSDaniel Ribeiro } 958385f9cbSDaniel Ribeiro 9699fc5131SLinus Walleij static inline int pxamci_set_power(struct pxamci_host *host, 9799fc5131SLinus Walleij unsigned char power_mode, 9899fc5131SLinus Walleij unsigned int vdd) 998385f9cbSDaniel Ribeiro { 10061951fd6SDaniel Mack struct mmc_host *mmc = host->mmc; 10161951fd6SDaniel Mack struct regulator *supply = mmc->supply.vmmc; 102b405db6cSRobert Jarzmik 10361951fd6SDaniel Mack if (!IS_ERR(supply)) 10461951fd6SDaniel Mack return mmc_regulator_set_ocr(mmc, supply, vdd); 10599fc5131SLinus Walleij 106f54005b5SLinus Walleij if (host->power) { 107f54005b5SLinus Walleij bool on = !!((1 << vdd) & host->pdata->ocr_mask); 108f54005b5SLinus Walleij gpiod_set_value(host->power, on); 109b405db6cSRobert Jarzmik } 11061951fd6SDaniel Mack 11161951fd6SDaniel Mack if (host->pdata && host->pdata->setpower) 112a829abf8SArnd Bergmann return host->pdata->setpower(mmc_dev(host->mmc), vdd); 11399fc5131SLinus Walleij 11499fc5131SLinus Walleij return 0; 1158385f9cbSDaniel Ribeiro } 1168385f9cbSDaniel Ribeiro 1171c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host) 1181c6a0718SPierre Ossman { 1191c6a0718SPierre Ossman if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { 1201c6a0718SPierre Ossman unsigned long timeout = 10000; 1211c6a0718SPierre Ossman unsigned int v; 1221c6a0718SPierre Ossman 1231c6a0718SPierre Ossman writel(STOP_CLOCK, host->base + MMC_STRPCL); 1241c6a0718SPierre Ossman 1251c6a0718SPierre Ossman do { 1261c6a0718SPierre Ossman v = readl(host->base + MMC_STAT); 1271c6a0718SPierre Ossman if (!(v & STAT_CLK_EN)) 1281c6a0718SPierre Ossman break; 1291c6a0718SPierre Ossman udelay(1); 1301c6a0718SPierre Ossman } while (timeout--); 1311c6a0718SPierre Ossman 1321c6a0718SPierre Ossman if (v & STAT_CLK_EN) 1331c6a0718SPierre Ossman dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); 1341c6a0718SPierre Ossman } 1351c6a0718SPierre Ossman } 1361c6a0718SPierre Ossman 1371c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) 1381c6a0718SPierre Ossman { 1391c6a0718SPierre Ossman unsigned long flags; 1401c6a0718SPierre Ossman 1411c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags); 1421c6a0718SPierre Ossman host->imask &= ~mask; 1431c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 1441c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1451c6a0718SPierre Ossman } 1461c6a0718SPierre Ossman 1471c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) 1481c6a0718SPierre Ossman { 1491c6a0718SPierre Ossman unsigned long flags; 1501c6a0718SPierre Ossman 1511c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags); 1521c6a0718SPierre Ossman host->imask |= mask; 1531c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 1541c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1551c6a0718SPierre Ossman } 1561c6a0718SPierre Ossman 1576464b714SDaniel Mack static void pxamci_dma_irq(void *param); 1586464b714SDaniel Mack 1591c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) 1601c6a0718SPierre Ossman { 1616464b714SDaniel Mack struct dma_async_tx_descriptor *tx; 162e60a582bSArnd Bergmann enum dma_transfer_direction direction; 1636464b714SDaniel Mack struct dma_slave_config config; 1646464b714SDaniel Mack struct dma_chan *chan; 1651c6a0718SPierre Ossman unsigned int nob = data->blocks; 1661c6a0718SPierre Ossman unsigned long long clks; 1671c6a0718SPierre Ossman unsigned int timeout; 1686464b714SDaniel Mack int ret; 1691c6a0718SPierre Ossman 1701c6a0718SPierre Ossman host->data = data; 1711c6a0718SPierre Ossman 1721c6a0718SPierre Ossman writel(nob, host->base + MMC_NOB); 1731c6a0718SPierre Ossman writel(data->blksz, host->base + MMC_BLKLEN); 1741c6a0718SPierre Ossman 175ebebd9b0SRussell King clks = (unsigned long long)data->timeout_ns * host->clkrate; 1761c6a0718SPierre Ossman do_div(clks, 1000000000UL); 1771c6a0718SPierre Ossman timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); 1781c6a0718SPierre Ossman writel((timeout + 255) / 256, host->base + MMC_RDTO); 1791c6a0718SPierre Ossman 1806464b714SDaniel Mack memset(&config, 0, sizeof(config)); 1816464b714SDaniel Mack config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 1826464b714SDaniel Mack config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 1836464b714SDaniel Mack config.src_addr = host->res->start + MMC_RXFIFO; 1846464b714SDaniel Mack config.dst_addr = host->res->start + MMC_TXFIFO; 1856464b714SDaniel Mack config.src_maxburst = 32; 1866464b714SDaniel Mack config.dst_maxburst = 32; 1876464b714SDaniel Mack 1881c6a0718SPierre Ossman if (data->flags & MMC_DATA_READ) { 1891c6a0718SPierre Ossman host->dma_dir = DMA_FROM_DEVICE; 1906464b714SDaniel Mack direction = DMA_DEV_TO_MEM; 1916464b714SDaniel Mack chan = host->dma_chan_rx; 1921c6a0718SPierre Ossman } else { 1931c6a0718SPierre Ossman host->dma_dir = DMA_TO_DEVICE; 1946464b714SDaniel Mack direction = DMA_MEM_TO_DEV; 1956464b714SDaniel Mack chan = host->dma_chan_tx; 1961c6a0718SPierre Ossman } 1971c6a0718SPierre Ossman 1986464b714SDaniel Mack config.direction = direction; 1991c6a0718SPierre Ossman 2006464b714SDaniel Mack ret = dmaengine_slave_config(chan, &config); 2016464b714SDaniel Mack if (ret < 0) { 2026464b714SDaniel Mack dev_err(mmc_dev(host->mmc), "dma slave config failed\n"); 2036464b714SDaniel Mack return; 2046464b714SDaniel Mack } 2056464b714SDaniel Mack 2066464b714SDaniel Mack host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len, 2071c6a0718SPierre Ossman host->dma_dir); 2081c6a0718SPierre Ossman 2096464b714SDaniel Mack tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction, 2106464b714SDaniel Mack DMA_PREP_INTERRUPT); 2116464b714SDaniel Mack if (!tx) { 2126464b714SDaniel Mack dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n"); 2136464b714SDaniel Mack return; 2141c6a0718SPierre Ossman } 2151c6a0718SPierre Ossman 2166464b714SDaniel Mack if (!(data->flags & MMC_DATA_READ)) { 2176464b714SDaniel Mack tx->callback = pxamci_dma_irq; 2186464b714SDaniel Mack tx->callback_param = host; 2196464b714SDaniel Mack } 2206464b714SDaniel Mack 2216464b714SDaniel Mack host->dma_cookie = dmaengine_submit(tx); 222b6018958SCliff Brake 223b6018958SCliff Brake /* 224b6018958SCliff Brake * workaround for erratum #91: 225b6018958SCliff Brake * only start DMA now if we are doing a read, 226b6018958SCliff Brake * otherwise we wait until CMD/RESP has finished 227b6018958SCliff Brake * before starting DMA. 228b6018958SCliff Brake */ 229b6018958SCliff Brake if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) 2306464b714SDaniel Mack dma_async_issue_pending(chan); 2311c6a0718SPierre Ossman } 2321c6a0718SPierre Ossman 2331c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) 2341c6a0718SPierre Ossman { 2351c6a0718SPierre Ossman WARN_ON(host->cmd != NULL); 2361c6a0718SPierre Ossman host->cmd = cmd; 2371c6a0718SPierre Ossman 2381c6a0718SPierre Ossman if (cmd->flags & MMC_RSP_BUSY) 2391c6a0718SPierre Ossman cmdat |= CMDAT_BUSY; 2401c6a0718SPierre Ossman 2411c6a0718SPierre Ossman #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) 2421c6a0718SPierre Ossman switch (RSP_TYPE(mmc_resp_type(cmd))) { 2431c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ 2441c6a0718SPierre Ossman cmdat |= CMDAT_RESP_SHORT; 2451c6a0718SPierre Ossman break; 2461c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R3): 2471c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R3; 2481c6a0718SPierre Ossman break; 2491c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R2): 2501c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R2; 2511c6a0718SPierre Ossman break; 2521c6a0718SPierre Ossman default: 2531c6a0718SPierre Ossman break; 2541c6a0718SPierre Ossman } 2551c6a0718SPierre Ossman 2561c6a0718SPierre Ossman writel(cmd->opcode, host->base + MMC_CMD); 2571c6a0718SPierre Ossman writel(cmd->arg >> 16, host->base + MMC_ARGH); 2581c6a0718SPierre Ossman writel(cmd->arg & 0xffff, host->base + MMC_ARGL); 2591c6a0718SPierre Ossman writel(cmdat, host->base + MMC_CMDAT); 2601c6a0718SPierre Ossman writel(host->clkrt, host->base + MMC_CLKRT); 2611c6a0718SPierre Ossman 2621c6a0718SPierre Ossman writel(START_CLOCK, host->base + MMC_STRPCL); 2631c6a0718SPierre Ossman 2641c6a0718SPierre Ossman pxamci_enable_irq(host, END_CMD_RES); 2651c6a0718SPierre Ossman } 2661c6a0718SPierre Ossman 2671c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) 2681c6a0718SPierre Ossman { 2691c6a0718SPierre Ossman host->mrq = NULL; 2701c6a0718SPierre Ossman host->cmd = NULL; 2711c6a0718SPierre Ossman host->data = NULL; 2721c6a0718SPierre Ossman mmc_request_done(host->mmc, mrq); 2731c6a0718SPierre Ossman } 2741c6a0718SPierre Ossman 2751c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) 2761c6a0718SPierre Ossman { 2771c6a0718SPierre Ossman struct mmc_command *cmd = host->cmd; 2781c6a0718SPierre Ossman int i; 2791c6a0718SPierre Ossman u32 v; 2801c6a0718SPierre Ossman 2811c6a0718SPierre Ossman if (!cmd) 2821c6a0718SPierre Ossman return 0; 2831c6a0718SPierre Ossman 2841c6a0718SPierre Ossman host->cmd = NULL; 2851c6a0718SPierre Ossman 2861c6a0718SPierre Ossman /* 2871c6a0718SPierre Ossman * Did I mention this is Sick. We always need to 2881c6a0718SPierre Ossman * discard the upper 8 bits of the first 16-bit word. 2891c6a0718SPierre Ossman */ 2901c6a0718SPierre Ossman v = readl(host->base + MMC_RES) & 0xffff; 2911c6a0718SPierre Ossman for (i = 0; i < 4; i++) { 2921c6a0718SPierre Ossman u32 w1 = readl(host->base + MMC_RES) & 0xffff; 2931c6a0718SPierre Ossman u32 w2 = readl(host->base + MMC_RES) & 0xffff; 2941c6a0718SPierre Ossman cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; 2951c6a0718SPierre Ossman v = w2; 2961c6a0718SPierre Ossman } 2971c6a0718SPierre Ossman 2981c6a0718SPierre Ossman if (stat & STAT_TIME_OUT_RESPONSE) { 29917b0429dSPierre Ossman cmd->error = -ETIMEDOUT; 3001c6a0718SPierre Ossman } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { 3011c6a0718SPierre Ossman /* 3021c6a0718SPierre Ossman * workaround for erratum #42: 3031c6a0718SPierre Ossman * Intel PXA27x Family Processor Specification Update Rev 001 30490e07d9fSNicolas Pitre * A bogus CRC error can appear if the msb of a 136 bit 30590e07d9fSNicolas Pitre * response is a one. 3061c6a0718SPierre Ossman */ 307e10a854cSCliff Brake if (cpu_is_pxa27x() && 308e10a854cSCliff Brake (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000)) 3091c6a0718SPierre Ossman pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); 310e10a854cSCliff Brake else 31117b0429dSPierre Ossman cmd->error = -EILSEQ; 3121c6a0718SPierre Ossman } 3131c6a0718SPierre Ossman 3141c6a0718SPierre Ossman pxamci_disable_irq(host, END_CMD_RES); 31517b0429dSPierre Ossman if (host->data && !cmd->error) { 3161c6a0718SPierre Ossman pxamci_enable_irq(host, DATA_TRAN_DONE); 317b6018958SCliff Brake /* 318b6018958SCliff Brake * workaround for erratum #91, if doing write 319b6018958SCliff Brake * enable DMA late 320b6018958SCliff Brake */ 321b6018958SCliff Brake if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) 3226464b714SDaniel Mack dma_async_issue_pending(host->dma_chan_tx); 3231c6a0718SPierre Ossman } else { 3241c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq); 3251c6a0718SPierre Ossman } 3261c6a0718SPierre Ossman 3271c6a0718SPierre Ossman return 1; 3281c6a0718SPierre Ossman } 3291c6a0718SPierre Ossman 3301c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) 3311c6a0718SPierre Ossman { 3321c6a0718SPierre Ossman struct mmc_data *data = host->data; 3336464b714SDaniel Mack struct dma_chan *chan; 3341c6a0718SPierre Ossman 3351c6a0718SPierre Ossman if (!data) 3361c6a0718SPierre Ossman return 0; 3371c6a0718SPierre Ossman 3386464b714SDaniel Mack if (data->flags & MMC_DATA_READ) 3396464b714SDaniel Mack chan = host->dma_chan_rx; 3406464b714SDaniel Mack else 3416464b714SDaniel Mack chan = host->dma_chan_tx; 3426464b714SDaniel Mack dma_unmap_sg(chan->device->dev, 3436464b714SDaniel Mack data->sg, data->sg_len, host->dma_dir); 3441c6a0718SPierre Ossman 3451c6a0718SPierre Ossman if (stat & STAT_READ_TIME_OUT) 34617b0429dSPierre Ossman data->error = -ETIMEDOUT; 3471c6a0718SPierre Ossman else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) 34817b0429dSPierre Ossman data->error = -EILSEQ; 3491c6a0718SPierre Ossman 3501c6a0718SPierre Ossman /* 3511c6a0718SPierre Ossman * There appears to be a hardware design bug here. There seems to 3521c6a0718SPierre Ossman * be no way to find out how much data was transferred to the card. 3531c6a0718SPierre Ossman * This means that if there was an error on any block, we mark all 3541c6a0718SPierre Ossman * data blocks as being in error. 3551c6a0718SPierre Ossman */ 35617b0429dSPierre Ossman if (!data->error) 3571c6a0718SPierre Ossman data->bytes_xfered = data->blocks * data->blksz; 3581c6a0718SPierre Ossman else 3591c6a0718SPierre Ossman data->bytes_xfered = 0; 3601c6a0718SPierre Ossman 3611c6a0718SPierre Ossman pxamci_disable_irq(host, DATA_TRAN_DONE); 3621c6a0718SPierre Ossman 3631c6a0718SPierre Ossman host->data = NULL; 3641c6a0718SPierre Ossman if (host->mrq->stop) { 3651c6a0718SPierre Ossman pxamci_stop_clock(host); 366df456f47SBridge Wu pxamci_start_cmd(host, host->mrq->stop, host->cmdat); 3671c6a0718SPierre Ossman } else { 3681c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq); 3691c6a0718SPierre Ossman } 3701c6a0718SPierre Ossman 3711c6a0718SPierre Ossman return 1; 3721c6a0718SPierre Ossman } 3731c6a0718SPierre Ossman 3741c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid) 3751c6a0718SPierre Ossman { 3761c6a0718SPierre Ossman struct pxamci_host *host = devid; 3771c6a0718SPierre Ossman unsigned int ireg; 3781c6a0718SPierre Ossman int handled = 0; 3791c6a0718SPierre Ossman 38081ab570fSBridge Wu ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); 3811c6a0718SPierre Ossman 3821c6a0718SPierre Ossman if (ireg) { 3831c6a0718SPierre Ossman unsigned stat = readl(host->base + MMC_STAT); 3841c6a0718SPierre Ossman 3851c6a0718SPierre Ossman pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); 3861c6a0718SPierre Ossman 3871c6a0718SPierre Ossman if (ireg & END_CMD_RES) 3881c6a0718SPierre Ossman handled |= pxamci_cmd_done(host, stat); 3891c6a0718SPierre Ossman if (ireg & DATA_TRAN_DONE) 3901c6a0718SPierre Ossman handled |= pxamci_data_done(host, stat); 3915d3ad4e8SBridge Wu if (ireg & SDIO_INT) { 3925d3ad4e8SBridge Wu mmc_signal_sdio_irq(host->mmc); 3935d3ad4e8SBridge Wu handled = 1; 3945d3ad4e8SBridge Wu } 3951c6a0718SPierre Ossman } 3961c6a0718SPierre Ossman 3971c6a0718SPierre Ossman return IRQ_RETVAL(handled); 3981c6a0718SPierre Ossman } 3991c6a0718SPierre Ossman 4001c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) 4011c6a0718SPierre Ossman { 4021c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 4031c6a0718SPierre Ossman unsigned int cmdat; 4041c6a0718SPierre Ossman 4051c6a0718SPierre Ossman WARN_ON(host->mrq != NULL); 4061c6a0718SPierre Ossman 4071c6a0718SPierre Ossman host->mrq = mrq; 4081c6a0718SPierre Ossman 4091c6a0718SPierre Ossman pxamci_stop_clock(host); 4101c6a0718SPierre Ossman 4111c6a0718SPierre Ossman cmdat = host->cmdat; 4121c6a0718SPierre Ossman host->cmdat &= ~CMDAT_INIT; 4131c6a0718SPierre Ossman 4141c6a0718SPierre Ossman if (mrq->data) { 4151c6a0718SPierre Ossman pxamci_setup_data(host, mrq->data); 4161c6a0718SPierre Ossman 4171c6a0718SPierre Ossman cmdat &= ~CMDAT_BUSY; 4181c6a0718SPierre Ossman cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; 4191c6a0718SPierre Ossman if (mrq->data->flags & MMC_DATA_WRITE) 4201c6a0718SPierre Ossman cmdat |= CMDAT_WRITE; 4211c6a0718SPierre Ossman } 4221c6a0718SPierre Ossman 4231c6a0718SPierre Ossman pxamci_start_cmd(host, mrq->cmd, cmdat); 4241c6a0718SPierre Ossman } 4251c6a0718SPierre Ossman 4261c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc) 4271c6a0718SPierre Ossman { 4281c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 4291c6a0718SPierre Ossman 430c914a27cSLinus Walleij if (host->use_ro_gpio) 431fd546ee6SRobert Jarzmik return mmc_gpio_get_ro(mmc); 4321c6a0718SPierre Ossman if (host->pdata && host->pdata->get_ro) 43308f80bb5SAnton Vorontsov return !!host->pdata->get_ro(mmc_dev(mmc)); 43408f80bb5SAnton Vorontsov /* 43508f80bb5SAnton Vorontsov * Board doesn't support read only detection; let the mmc core 43608f80bb5SAnton Vorontsov * decide what to do. 43708f80bb5SAnton Vorontsov */ 43808f80bb5SAnton Vorontsov return -ENOSYS; 4391c6a0718SPierre Ossman } 4401c6a0718SPierre Ossman 4411c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 4421c6a0718SPierre Ossman { 4431c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 4441c6a0718SPierre Ossman 4451c6a0718SPierre Ossman if (ios->clock) { 446ebebd9b0SRussell King unsigned long rate = host->clkrate; 447ebebd9b0SRussell King unsigned int clk = rate / ios->clock; 448ebebd9b0SRussell King 449d8cb70d1SRussell King if (host->clkrt == CLKRT_OFF) 450e7370819SRobert Jarzmik clk_prepare_enable(host->clk); 451d8cb70d1SRussell King 45264eb036aSBridge Wu if (ios->clock == 26000000) { 453fa3f9938SHaojian Zhuang /* to support 26MHz */ 45464eb036aSBridge Wu host->clkrt = 7; 45564eb036aSBridge Wu } else { 45664eb036aSBridge Wu /* to handle (19.5MHz, 26MHz) */ 45764eb036aSBridge Wu if (!clk) 45864eb036aSBridge Wu clk = 1; 45964eb036aSBridge Wu 460ebebd9b0SRussell King /* 461ebebd9b0SRussell King * clk might result in a lower divisor than we 462ebebd9b0SRussell King * desire. check for that condition and adjust 463ebebd9b0SRussell King * as appropriate. 464ebebd9b0SRussell King */ 465ebebd9b0SRussell King if (rate / clk > ios->clock) 4661c6a0718SPierre Ossman clk <<= 1; 4671c6a0718SPierre Ossman host->clkrt = fls(clk) - 1; 46864eb036aSBridge Wu } 4691c6a0718SPierre Ossman 4701c6a0718SPierre Ossman /* 4711c6a0718SPierre Ossman * we write clkrt on the next command 4721c6a0718SPierre Ossman */ 4731c6a0718SPierre Ossman } else { 4741c6a0718SPierre Ossman pxamci_stop_clock(host); 475d8cb70d1SRussell King if (host->clkrt != CLKRT_OFF) { 476d8cb70d1SRussell King host->clkrt = CLKRT_OFF; 477e7370819SRobert Jarzmik clk_disable_unprepare(host->clk); 4781c6a0718SPierre Ossman } 479d8cb70d1SRussell King } 4801c6a0718SPierre Ossman 4811c6a0718SPierre Ossman if (host->power_mode != ios->power_mode) { 48299fc5131SLinus Walleij int ret; 48399fc5131SLinus Walleij 4841c6a0718SPierre Ossman host->power_mode = ios->power_mode; 4851c6a0718SPierre Ossman 48699fc5131SLinus Walleij ret = pxamci_set_power(host, ios->power_mode, ios->vdd); 48799fc5131SLinus Walleij if (ret) { 48899fc5131SLinus Walleij dev_err(mmc_dev(mmc), "unable to set power\n"); 48999fc5131SLinus Walleij /* 49099fc5131SLinus Walleij * The .set_ios() function in the mmc_host_ops 49199fc5131SLinus Walleij * struct return void, and failing to set the 49299fc5131SLinus Walleij * power should be rare so we print an error and 49399fc5131SLinus Walleij * return here. 49499fc5131SLinus Walleij */ 49599fc5131SLinus Walleij return; 49699fc5131SLinus Walleij } 4971c6a0718SPierre Ossman 4981c6a0718SPierre Ossman if (ios->power_mode == MMC_POWER_ON) 4991c6a0718SPierre Ossman host->cmdat |= CMDAT_INIT; 5001c6a0718SPierre Ossman } 5011c6a0718SPierre Ossman 502df456f47SBridge Wu if (ios->bus_width == MMC_BUS_WIDTH_4) 503df456f47SBridge Wu host->cmdat |= CMDAT_SD_4DAT; 504df456f47SBridge Wu else 505df456f47SBridge Wu host->cmdat &= ~CMDAT_SD_4DAT; 506df456f47SBridge Wu 50799fc5131SLinus Walleij dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n", 5081c6a0718SPierre Ossman host->clkrt, host->cmdat); 5091c6a0718SPierre Ossman } 5101c6a0718SPierre Ossman 5115d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) 5125d3ad4e8SBridge Wu { 5135d3ad4e8SBridge Wu struct pxamci_host *pxa_host = mmc_priv(host); 5145d3ad4e8SBridge Wu 5155d3ad4e8SBridge Wu if (enable) 5165d3ad4e8SBridge Wu pxamci_enable_irq(pxa_host, SDIO_INT); 5175d3ad4e8SBridge Wu else 5185d3ad4e8SBridge Wu pxamci_disable_irq(pxa_host, SDIO_INT); 5195d3ad4e8SBridge Wu } 5205d3ad4e8SBridge Wu 5211c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = { 5221c6a0718SPierre Ossman .request = pxamci_request, 523fd546ee6SRobert Jarzmik .get_cd = mmc_gpio_get_cd, 5241c6a0718SPierre Ossman .get_ro = pxamci_get_ro, 5251c6a0718SPierre Ossman .set_ios = pxamci_set_ios, 5265d3ad4e8SBridge Wu .enable_sdio_irq = pxamci_enable_sdio_irq, 5271c6a0718SPierre Ossman }; 5281c6a0718SPierre Ossman 5296464b714SDaniel Mack static void pxamci_dma_irq(void *param) 5301c6a0718SPierre Ossman { 5316464b714SDaniel Mack struct pxamci_host *host = param; 5326464b714SDaniel Mack struct dma_tx_state state; 5336464b714SDaniel Mack enum dma_status status; 5346464b714SDaniel Mack struct dma_chan *chan; 5356464b714SDaniel Mack unsigned long flags; 536c783837bSNicolas Pitre 5376464b714SDaniel Mack spin_lock_irqsave(&host->lock, flags); 5386464b714SDaniel Mack 5396464b714SDaniel Mack if (!host->data) 5406464b714SDaniel Mack goto out_unlock; 5416464b714SDaniel Mack 5426464b714SDaniel Mack if (host->data->flags & MMC_DATA_READ) 5436464b714SDaniel Mack chan = host->dma_chan_rx; 5446464b714SDaniel Mack else 5456464b714SDaniel Mack chan = host->dma_chan_tx; 5466464b714SDaniel Mack 5476464b714SDaniel Mack status = dmaengine_tx_status(chan, host->dma_cookie, &state); 5486464b714SDaniel Mack 5496464b714SDaniel Mack if (likely(status == DMA_COMPLETE)) { 550c783837bSNicolas Pitre writel(BUF_PART_FULL, host->base + MMC_PRTBUF); 551c783837bSNicolas Pitre } else { 5526464b714SDaniel Mack pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc), 5536464b714SDaniel Mack host->data->flags & MMC_DATA_READ ? "rx" : "tx"); 554c783837bSNicolas Pitre host->data->error = -EIO; 555c783837bSNicolas Pitre pxamci_data_done(host, 0); 556c783837bSNicolas Pitre } 5576464b714SDaniel Mack 5586464b714SDaniel Mack out_unlock: 5596464b714SDaniel Mack spin_unlock_irqrestore(&host->lock, flags); 5601c6a0718SPierre Ossman } 5611c6a0718SPierre Ossman 5621c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid) 5631c6a0718SPierre Ossman { 5641c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(devid); 5651c6a0718SPierre Ossman 56638a8dda9SDaniel Mack mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms)); 5671c6a0718SPierre Ossman return IRQ_HANDLED; 5681c6a0718SPierre Ossman } 5691c6a0718SPierre Ossman 570e6027b46SDaniel Mack #ifdef CONFIG_OF 571e6027b46SDaniel Mack static const struct of_device_id pxa_mmc_dt_ids[] = { 572e6027b46SDaniel Mack { .compatible = "marvell,pxa-mmc" }, 573e6027b46SDaniel Mack { } 574e6027b46SDaniel Mack }; 575e6027b46SDaniel Mack 576e6027b46SDaniel Mack MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids); 577e6027b46SDaniel Mack 578fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev, 579fa3a5115SDaniel Mack struct mmc_host *mmc) 580e6027b46SDaniel Mack { 581e6027b46SDaniel Mack struct device_node *np = pdev->dev.of_node; 58238a8dda9SDaniel Mack struct pxamci_host *host = mmc_priv(mmc); 583e6027b46SDaniel Mack u32 tmp; 584fa3a5115SDaniel Mack int ret; 585e6027b46SDaniel Mack 586e6027b46SDaniel Mack if (!np) 587e6027b46SDaniel Mack return 0; 588e6027b46SDaniel Mack 589e6027b46SDaniel Mack /* pxa-mmc specific */ 590e6027b46SDaniel Mack if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0) 59138a8dda9SDaniel Mack host->detect_delay_ms = tmp; 592e6027b46SDaniel Mack 593fa3a5115SDaniel Mack ret = mmc_of_parse(mmc); 594fa3a5115SDaniel Mack if (ret < 0) 595fa3a5115SDaniel Mack return ret; 596fa3a5115SDaniel Mack 597e6027b46SDaniel Mack return 0; 598e6027b46SDaniel Mack } 599e6027b46SDaniel Mack #else 600fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev, 601fa3a5115SDaniel Mack struct mmc_host *mmc) 602e6027b46SDaniel Mack { 603e6027b46SDaniel Mack return 0; 604e6027b46SDaniel Mack } 605e6027b46SDaniel Mack #endif 606e6027b46SDaniel Mack 6071c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev) 6081c6a0718SPierre Ossman { 6091c6a0718SPierre Ossman struct mmc_host *mmc; 6101c6a0718SPierre Ossman struct pxamci_host *host = NULL; 61123f3ff72SDaniel Mack struct device *dev = &pdev->dev; 6126b3348f9SRobert Jarzmik struct resource *r; 61338a8dda9SDaniel Mack int ret, irq; 6141c6a0718SPierre Ossman 6151c6a0718SPierre Ossman irq = platform_get_irq(pdev, 0); 61607e7716cSRobert Jarzmik if (irq < 0) 61707e7716cSRobert Jarzmik return irq; 6181c6a0718SPierre Ossman 61923f3ff72SDaniel Mack mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev); 6201c6a0718SPierre Ossman if (!mmc) { 6211c6a0718SPierre Ossman ret = -ENOMEM; 6221c6a0718SPierre Ossman goto out; 6231c6a0718SPierre Ossman } 6241c6a0718SPierre Ossman 6251c6a0718SPierre Ossman mmc->ops = &pxamci_ops; 6261c6a0718SPierre Ossman 6271c6a0718SPierre Ossman /* 6281c6a0718SPierre Ossman * We can do SG-DMA, but we don't because we never know how much 6291c6a0718SPierre Ossman * data we successfully wrote to the card. 6301c6a0718SPierre Ossman */ 631a36274e0SMartin K. Petersen mmc->max_segs = NR_SG; 6321c6a0718SPierre Ossman 6331c6a0718SPierre Ossman /* 6341c6a0718SPierre Ossman * Our hardware DMA can handle a maximum of one page per SG entry. 6351c6a0718SPierre Ossman */ 6361c6a0718SPierre Ossman mmc->max_seg_size = PAGE_SIZE; 6371c6a0718SPierre Ossman 6381c6a0718SPierre Ossman /* 639fe2dc44eSNicolas Pitre * Block length register is only 10 bits before PXA27x. 6401c6a0718SPierre Ossman */ 6410ffcbfd5SEric Miao mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048; 6421c6a0718SPierre Ossman 6431c6a0718SPierre Ossman /* 6441c6a0718SPierre Ossman * Block count register is 16 bits. 6451c6a0718SPierre Ossman */ 6461c6a0718SPierre Ossman mmc->max_blk_count = 65535; 6471c6a0718SPierre Ossman 648fa3a5115SDaniel Mack ret = pxamci_of_init(pdev, mmc); 649fa3a5115SDaniel Mack if (ret) 65098d7c5e5SChristophe JAILLET goto out; 651fa3a5115SDaniel Mack 6521c6a0718SPierre Ossman host = mmc_priv(mmc); 6531c6a0718SPierre Ossman host->mmc = mmc; 6541c6a0718SPierre Ossman host->pdata = pdev->dev.platform_data; 655d8cb70d1SRussell King host->clkrt = CLKRT_OFF; 656ebebd9b0SRussell King 65723f3ff72SDaniel Mack host->clk = devm_clk_get(dev, NULL); 658ebebd9b0SRussell King if (IS_ERR(host->clk)) { 659ebebd9b0SRussell King ret = PTR_ERR(host->clk); 660ebebd9b0SRussell King host->clk = NULL; 661ebebd9b0SRussell King goto out; 662ebebd9b0SRussell King } 663ebebd9b0SRussell King 664ebebd9b0SRussell King host->clkrate = clk_get_rate(host->clk); 665ebebd9b0SRussell King 666ebebd9b0SRussell King /* 667ebebd9b0SRussell King * Calculate minimum clock rate, rounding up. 668ebebd9b0SRussell King */ 669ebebd9b0SRussell King mmc->f_min = (host->clkrate + 63) / 64; 670fa3f9938SHaojian Zhuang mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate; 671ebebd9b0SRussell King 67261951fd6SDaniel Mack ret = pxamci_init_ocr(host); 67361951fd6SDaniel Mack if (ret < 0) 674b886f54cSChristophe JAILLET goto out; 6758385f9cbSDaniel Ribeiro 676de3ee99bSLinus Walleij mmc->caps = 0; 6775d3ad4e8SBridge Wu host->cmdat = 0; 6780ffcbfd5SEric Miao if (!cpu_is_pxa25x()) { 6795d3ad4e8SBridge Wu mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; 6805d3ad4e8SBridge Wu host->cmdat |= CMDAT_SDIO_INT_EN; 681fa3f9938SHaojian Zhuang if (mmc_has_26MHz()) 68264eb036aSBridge Wu mmc->caps |= MMC_CAP_MMC_HIGHSPEED | 68364eb036aSBridge Wu MMC_CAP_SD_HIGHSPEED; 6845d3ad4e8SBridge Wu } 6851c6a0718SPierre Ossman 6861c6a0718SPierre Ossman spin_lock_init(&host->lock); 6871c6a0718SPierre Ossman host->imask = MMC_I_MASK_ALL; 6881c6a0718SPierre Ossman 689*c89a869bSYangtao Li host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); 69007e7716cSRobert Jarzmik if (IS_ERR(host->base)) { 69107e7716cSRobert Jarzmik ret = PTR_ERR(host->base); 6921c6a0718SPierre Ossman goto out; 6931c6a0718SPierre Ossman } 694*c89a869bSYangtao Li host->res = r; 6951c6a0718SPierre Ossman 6961c6a0718SPierre Ossman /* 6971c6a0718SPierre Ossman * Ensure that the host controller is shut down, and setup 6981c6a0718SPierre Ossman * with our defaults. 6991c6a0718SPierre Ossman */ 7001c6a0718SPierre Ossman pxamci_stop_clock(host); 7011c6a0718SPierre Ossman writel(0, host->base + MMC_SPI); 7021c6a0718SPierre Ossman writel(64, host->base + MMC_RESTO); 7031c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 7041c6a0718SPierre Ossman 70523f3ff72SDaniel Mack ret = devm_request_irq(dev, irq, pxamci_irq, 0, 70607e7716cSRobert Jarzmik DRIVER_NAME, host); 7071c6a0718SPierre Ossman if (ret) 7081c6a0718SPierre Ossman goto out; 7091c6a0718SPierre Ossman 7101c6a0718SPierre Ossman platform_set_drvdata(pdev, mmc); 7111c6a0718SPierre Ossman 712e1ebb456SPeter Ujfalusi host->dma_chan_rx = dma_request_chan(dev, "rx"); 713e1ebb456SPeter Ujfalusi if (IS_ERR(host->dma_chan_rx)) { 71423f3ff72SDaniel Mack dev_err(dev, "unable to request rx dma channel\n"); 715e1ebb456SPeter Ujfalusi ret = PTR_ERR(host->dma_chan_rx); 716e1ebb456SPeter Ujfalusi host->dma_chan_rx = NULL; 7176464b714SDaniel Mack goto out; 7186464b714SDaniel Mack } 7196464b714SDaniel Mack 720e1ebb456SPeter Ujfalusi host->dma_chan_tx = dma_request_chan(dev, "tx"); 721e1ebb456SPeter Ujfalusi if (IS_ERR(host->dma_chan_tx)) { 72223f3ff72SDaniel Mack dev_err(dev, "unable to request tx dma channel\n"); 723e1ebb456SPeter Ujfalusi ret = PTR_ERR(host->dma_chan_tx); 724e1ebb456SPeter Ujfalusi host->dma_chan_tx = NULL; 7256464b714SDaniel Mack goto out; 7266464b714SDaniel Mack } 7279a788c6bSBridge Wu 728b405db6cSRobert Jarzmik if (host->pdata) { 72938a8dda9SDaniel Mack host->detect_delay_ms = host->pdata->detect_delay_ms; 73038a8dda9SDaniel Mack 731f54005b5SLinus Walleij host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); 732f54005b5SLinus Walleij if (IS_ERR(host->power)) { 733d7b819b5SZhihao Cheng ret = PTR_ERR(host->power); 734f54005b5SLinus Walleij dev_err(dev, "Failed requesting gpio_power\n"); 735b405db6cSRobert Jarzmik goto out; 736b405db6cSRobert Jarzmik } 73738a8dda9SDaniel Mack 738c914a27cSLinus Walleij /* FIXME: should we pass detection delay to debounce? */ 739d0052ad9SMichał Mirosław ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); 740c914a27cSLinus Walleij if (ret && ret != -ENOENT) { 741c914a27cSLinus Walleij dev_err(dev, "Failed requesting gpio_cd\n"); 742c914a27cSLinus Walleij goto out; 743c914a27cSLinus Walleij } 744c914a27cSLinus Walleij 7459073d10bSMichał Mirosław if (!host->pdata->gpio_card_ro_invert) 7469073d10bSMichał Mirosław mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; 7479073d10bSMichał Mirosław 748d0052ad9SMichał Mirosław ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0); 749c914a27cSLinus Walleij if (ret && ret != -ENOENT) { 750c914a27cSLinus Walleij dev_err(dev, "Failed requesting gpio_ro\n"); 751c914a27cSLinus Walleij goto out; 752c914a27cSLinus Walleij } 7539073d10bSMichał Mirosław if (!ret) 754c914a27cSLinus Walleij host->use_ro_gpio = true; 755b405db6cSRobert Jarzmik 75638a8dda9SDaniel Mack if (host->pdata->init) 75723f3ff72SDaniel Mack host->pdata->init(dev, pxamci_detect_irq, mmc); 7581c6a0718SPierre Ossman 759f54005b5SLinus Walleij if (host->power && host->pdata->setpower) 76023f3ff72SDaniel Mack dev_warn(dev, "gpio_power and setpower() both defined\n"); 761c914a27cSLinus Walleij if (host->use_ro_gpio && host->pdata->get_ro) 76223f3ff72SDaniel Mack dev_warn(dev, "gpio_ro and get_ro() both defined\n"); 76338a8dda9SDaniel Mack } 764b405db6cSRobert Jarzmik 76580e1ef3aSYang Yingliang ret = mmc_add_host(mmc); 76680e1ef3aSYang Yingliang if (ret) { 76780e1ef3aSYang Yingliang if (host->pdata && host->pdata->exit) 76880e1ef3aSYang Yingliang host->pdata->exit(dev, mmc); 76980e1ef3aSYang Yingliang goto out; 77080e1ef3aSYang Yingliang } 7711c6a0718SPierre Ossman 7721c6a0718SPierre Ossman return 0; 7731c6a0718SPierre Ossman 7741c6a0718SPierre Ossman out: 7751c6a0718SPierre Ossman if (host) { 7766464b714SDaniel Mack if (host->dma_chan_rx) 7776464b714SDaniel Mack dma_release_channel(host->dma_chan_rx); 7786464b714SDaniel Mack if (host->dma_chan_tx) 7796464b714SDaniel Mack dma_release_channel(host->dma_chan_tx); 7801c6a0718SPierre Ossman } 7811c6a0718SPierre Ossman if (mmc) 7821c6a0718SPierre Ossman mmc_free_host(mmc); 7831c6a0718SPierre Ossman return ret; 7841c6a0718SPierre Ossman } 7851c6a0718SPierre Ossman 7861c6a0718SPierre Ossman static int pxamci_remove(struct platform_device *pdev) 7871c6a0718SPierre Ossman { 7881c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(pdev); 7891c6a0718SPierre Ossman 7901c6a0718SPierre Ossman if (mmc) { 7911c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 7921c6a0718SPierre Ossman 7935d6b1edfSDaniel Mack mmc_remove_host(mmc); 7945d6b1edfSDaniel Mack 7951c6a0718SPierre Ossman if (host->pdata && host->pdata->exit) 7961c6a0718SPierre Ossman host->pdata->exit(&pdev->dev, mmc); 7971c6a0718SPierre Ossman 7981c6a0718SPierre Ossman pxamci_stop_clock(host); 7991c6a0718SPierre Ossman writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| 8001c6a0718SPierre Ossman END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, 8011c6a0718SPierre Ossman host->base + MMC_I_MASK); 8021c6a0718SPierre Ossman 8036464b714SDaniel Mack dmaengine_terminate_all(host->dma_chan_rx); 8046464b714SDaniel Mack dmaengine_terminate_all(host->dma_chan_tx); 8056464b714SDaniel Mack dma_release_channel(host->dma_chan_rx); 8066464b714SDaniel Mack dma_release_channel(host->dma_chan_tx); 8071c6a0718SPierre Ossman 8081c6a0718SPierre Ossman mmc_free_host(mmc); 8091c6a0718SPierre Ossman } 81052c09186SDaniel Mack 8111c6a0718SPierre Ossman return 0; 8121c6a0718SPierre Ossman } 8131c6a0718SPierre Ossman 8141c6a0718SPierre Ossman static struct platform_driver pxamci_driver = { 8151c6a0718SPierre Ossman .probe = pxamci_probe, 8161c6a0718SPierre Ossman .remove = pxamci_remove, 8171c6a0718SPierre Ossman .driver = { 8181c6a0718SPierre Ossman .name = DRIVER_NAME, 81921b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 820e6027b46SDaniel Mack .of_match_table = of_match_ptr(pxa_mmc_dt_ids), 8211c6a0718SPierre Ossman }, 8221c6a0718SPierre Ossman }; 8231c6a0718SPierre Ossman 824d1f81a64SAxel Lin module_platform_driver(pxamci_driver); 8251c6a0718SPierre Ossman 8261c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); 8271c6a0718SPierre Ossman MODULE_LICENSE("GPL"); 828bc65c724SKay Sievers MODULE_ALIAS("platform:pxa2xx-mci"); 829