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>
3308d3df8cSArnd Bergmann #include <linux/soc/pxa/cpu.h>
341c6a0718SPierre Ossman
3587dfb311SMasahiro Yamada #include <linux/sizes.h>
361c6a0718SPierre Ossman
37293b2da1SArnd Bergmann #include <linux/platform_data/mmc-pxamci.h>
381c6a0718SPierre Ossman
391c6a0718SPierre Ossman #include "pxamci.h"
401c6a0718SPierre Ossman
411c6a0718SPierre Ossman #define DRIVER_NAME "pxa2xx-mci"
421c6a0718SPierre Ossman
431c6a0718SPierre Ossman #define NR_SG 1
44d8cb70d1SRussell King #define CLKRT_OFF (~0)
451c6a0718SPierre Ossman
46fa3f9938SHaojian Zhuang #define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310() \
47fa3f9938SHaojian Zhuang || cpu_is_pxa935())
48fa3f9938SHaojian Zhuang
491c6a0718SPierre Ossman struct pxamci_host {
501c6a0718SPierre Ossman struct mmc_host *mmc;
511c6a0718SPierre Ossman spinlock_t lock;
521c6a0718SPierre Ossman struct resource *res;
531c6a0718SPierre Ossman void __iomem *base;
54ebebd9b0SRussell King struct clk *clk;
55ebebd9b0SRussell King unsigned long clkrate;
561c6a0718SPierre Ossman unsigned int clkrt;
571c6a0718SPierre Ossman unsigned int cmdat;
581c6a0718SPierre Ossman unsigned int imask;
591c6a0718SPierre Ossman unsigned int power_mode;
6038a8dda9SDaniel Mack unsigned long detect_delay_ms;
61c914a27cSLinus Walleij bool use_ro_gpio;
62f54005b5SLinus Walleij struct gpio_desc *power;
631c6a0718SPierre Ossman struct pxamci_platform_data *pdata;
641c6a0718SPierre Ossman
651c6a0718SPierre Ossman struct mmc_request *mrq;
661c6a0718SPierre Ossman struct mmc_command *cmd;
671c6a0718SPierre Ossman struct mmc_data *data;
681c6a0718SPierre Ossman
696464b714SDaniel Mack struct dma_chan *dma_chan_rx;
706464b714SDaniel Mack struct dma_chan *dma_chan_tx;
716464b714SDaniel Mack dma_cookie_t dma_cookie;
721c6a0718SPierre Ossman unsigned int dma_len;
731c6a0718SPierre Ossman unsigned int dma_dir;
741c6a0718SPierre Ossman };
751c6a0718SPierre Ossman
pxamci_init_ocr(struct pxamci_host * host)7661951fd6SDaniel Mack static int pxamci_init_ocr(struct pxamci_host *host)
778385f9cbSDaniel Ribeiro {
7861951fd6SDaniel Mack struct mmc_host *mmc = host->mmc;
7961951fd6SDaniel Mack int ret;
808385f9cbSDaniel Ribeiro
8161951fd6SDaniel Mack ret = mmc_regulator_get_supply(mmc);
8261951fd6SDaniel Mack if (ret < 0)
8361951fd6SDaniel Mack return ret;
8461951fd6SDaniel Mack
8561951fd6SDaniel Mack if (IS_ERR(mmc->supply.vmmc)) {
868385f9cbSDaniel Ribeiro /* fall-back to platform data */
8761951fd6SDaniel Mack mmc->ocr_avail = host->pdata ?
888385f9cbSDaniel Ribeiro host->pdata->ocr_mask :
898385f9cbSDaniel Ribeiro MMC_VDD_32_33 | MMC_VDD_33_34;
908385f9cbSDaniel Ribeiro }
9161951fd6SDaniel Mack
9261951fd6SDaniel Mack return 0;
938385f9cbSDaniel Ribeiro }
948385f9cbSDaniel Ribeiro
pxamci_set_power(struct pxamci_host * host,unsigned char power_mode,unsigned int vdd)9599fc5131SLinus Walleij static inline int pxamci_set_power(struct pxamci_host *host,
9699fc5131SLinus Walleij unsigned char power_mode,
9799fc5131SLinus Walleij unsigned int vdd)
988385f9cbSDaniel Ribeiro {
9961951fd6SDaniel Mack struct mmc_host *mmc = host->mmc;
10061951fd6SDaniel Mack struct regulator *supply = mmc->supply.vmmc;
101b405db6cSRobert Jarzmik
10261951fd6SDaniel Mack if (!IS_ERR(supply))
10361951fd6SDaniel Mack return mmc_regulator_set_ocr(mmc, supply, vdd);
10499fc5131SLinus Walleij
105f54005b5SLinus Walleij if (host->power) {
106f54005b5SLinus Walleij bool on = !!((1 << vdd) & host->pdata->ocr_mask);
107f54005b5SLinus Walleij gpiod_set_value(host->power, on);
108b405db6cSRobert Jarzmik }
10961951fd6SDaniel Mack
11061951fd6SDaniel Mack if (host->pdata && host->pdata->setpower)
111a829abf8SArnd Bergmann return host->pdata->setpower(mmc_dev(host->mmc), vdd);
11299fc5131SLinus Walleij
11399fc5131SLinus Walleij return 0;
1148385f9cbSDaniel Ribeiro }
1158385f9cbSDaniel Ribeiro
pxamci_stop_clock(struct pxamci_host * host)1161c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host)
1171c6a0718SPierre Ossman {
1181c6a0718SPierre Ossman if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
1191c6a0718SPierre Ossman unsigned long timeout = 10000;
1201c6a0718SPierre Ossman unsigned int v;
1211c6a0718SPierre Ossman
1221c6a0718SPierre Ossman writel(STOP_CLOCK, host->base + MMC_STRPCL);
1231c6a0718SPierre Ossman
1241c6a0718SPierre Ossman do {
1251c6a0718SPierre Ossman v = readl(host->base + MMC_STAT);
1261c6a0718SPierre Ossman if (!(v & STAT_CLK_EN))
1271c6a0718SPierre Ossman break;
1281c6a0718SPierre Ossman udelay(1);
1291c6a0718SPierre Ossman } while (timeout--);
1301c6a0718SPierre Ossman
1311c6a0718SPierre Ossman if (v & STAT_CLK_EN)
1321c6a0718SPierre Ossman dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
1331c6a0718SPierre Ossman }
1341c6a0718SPierre Ossman }
1351c6a0718SPierre Ossman
pxamci_enable_irq(struct pxamci_host * host,unsigned int mask)1361c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
1371c6a0718SPierre Ossman {
1381c6a0718SPierre Ossman unsigned long flags;
1391c6a0718SPierre Ossman
1401c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags);
1411c6a0718SPierre Ossman host->imask &= ~mask;
1421c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK);
1431c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags);
1441c6a0718SPierre Ossman }
1451c6a0718SPierre Ossman
pxamci_disable_irq(struct pxamci_host * host,unsigned int mask)1461c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
1471c6a0718SPierre Ossman {
1481c6a0718SPierre Ossman unsigned long flags;
1491c6a0718SPierre Ossman
1501c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags);
1511c6a0718SPierre Ossman host->imask |= mask;
1521c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK);
1531c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags);
1541c6a0718SPierre Ossman }
1551c6a0718SPierre Ossman
1566464b714SDaniel Mack static void pxamci_dma_irq(void *param);
1576464b714SDaniel Mack
pxamci_setup_data(struct pxamci_host * host,struct mmc_data * data)1581c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
1591c6a0718SPierre Ossman {
1606464b714SDaniel Mack struct dma_async_tx_descriptor *tx;
161e60a582bSArnd Bergmann enum dma_transfer_direction direction;
1626464b714SDaniel Mack struct dma_slave_config config;
1636464b714SDaniel Mack struct dma_chan *chan;
1641c6a0718SPierre Ossman unsigned int nob = data->blocks;
1651c6a0718SPierre Ossman unsigned long long clks;
1661c6a0718SPierre Ossman unsigned int timeout;
1676464b714SDaniel Mack int ret;
1681c6a0718SPierre Ossman
1691c6a0718SPierre Ossman host->data = data;
1701c6a0718SPierre Ossman
1711c6a0718SPierre Ossman writel(nob, host->base + MMC_NOB);
1721c6a0718SPierre Ossman writel(data->blksz, host->base + MMC_BLKLEN);
1731c6a0718SPierre Ossman
174ebebd9b0SRussell King clks = (unsigned long long)data->timeout_ns * host->clkrate;
1751c6a0718SPierre Ossman do_div(clks, 1000000000UL);
1761c6a0718SPierre Ossman timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
1771c6a0718SPierre Ossman writel((timeout + 255) / 256, host->base + MMC_RDTO);
1781c6a0718SPierre Ossman
1796464b714SDaniel Mack memset(&config, 0, sizeof(config));
1806464b714SDaniel Mack config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1816464b714SDaniel Mack config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
1826464b714SDaniel Mack config.src_addr = host->res->start + MMC_RXFIFO;
1836464b714SDaniel Mack config.dst_addr = host->res->start + MMC_TXFIFO;
1846464b714SDaniel Mack config.src_maxburst = 32;
1856464b714SDaniel Mack config.dst_maxburst = 32;
1866464b714SDaniel Mack
1871c6a0718SPierre Ossman if (data->flags & MMC_DATA_READ) {
1881c6a0718SPierre Ossman host->dma_dir = DMA_FROM_DEVICE;
1896464b714SDaniel Mack direction = DMA_DEV_TO_MEM;
1906464b714SDaniel Mack chan = host->dma_chan_rx;
1911c6a0718SPierre Ossman } else {
1921c6a0718SPierre Ossman host->dma_dir = DMA_TO_DEVICE;
1936464b714SDaniel Mack direction = DMA_MEM_TO_DEV;
1946464b714SDaniel Mack chan = host->dma_chan_tx;
1951c6a0718SPierre Ossman }
1961c6a0718SPierre Ossman
1976464b714SDaniel Mack config.direction = direction;
1981c6a0718SPierre Ossman
1996464b714SDaniel Mack ret = dmaengine_slave_config(chan, &config);
2006464b714SDaniel Mack if (ret < 0) {
2016464b714SDaniel Mack dev_err(mmc_dev(host->mmc), "dma slave config failed\n");
2026464b714SDaniel Mack return;
2036464b714SDaniel Mack }
2046464b714SDaniel Mack
2056464b714SDaniel Mack host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
2061c6a0718SPierre Ossman host->dma_dir);
2071c6a0718SPierre Ossman
2086464b714SDaniel Mack tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction,
2096464b714SDaniel Mack DMA_PREP_INTERRUPT);
2106464b714SDaniel Mack if (!tx) {
2116464b714SDaniel Mack dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n");
2126464b714SDaniel Mack return;
2131c6a0718SPierre Ossman }
2141c6a0718SPierre Ossman
2156464b714SDaniel Mack if (!(data->flags & MMC_DATA_READ)) {
2166464b714SDaniel Mack tx->callback = pxamci_dma_irq;
2176464b714SDaniel Mack tx->callback_param = host;
2186464b714SDaniel Mack }
2196464b714SDaniel Mack
2206464b714SDaniel Mack host->dma_cookie = dmaengine_submit(tx);
221b6018958SCliff Brake
222b6018958SCliff Brake /*
223b6018958SCliff Brake * workaround for erratum #91:
224b6018958SCliff Brake * only start DMA now if we are doing a read,
225b6018958SCliff Brake * otherwise we wait until CMD/RESP has finished
226b6018958SCliff Brake * before starting DMA.
227b6018958SCliff Brake */
228b6018958SCliff Brake if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
2296464b714SDaniel Mack dma_async_issue_pending(chan);
2301c6a0718SPierre Ossman }
2311c6a0718SPierre Ossman
pxamci_start_cmd(struct pxamci_host * host,struct mmc_command * cmd,unsigned int cmdat)2321c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
2331c6a0718SPierre Ossman {
2341c6a0718SPierre Ossman WARN_ON(host->cmd != NULL);
2351c6a0718SPierre Ossman host->cmd = cmd;
2361c6a0718SPierre Ossman
2371c6a0718SPierre Ossman if (cmd->flags & MMC_RSP_BUSY)
2381c6a0718SPierre Ossman cmdat |= CMDAT_BUSY;
2391c6a0718SPierre Ossman
2401c6a0718SPierre Ossman #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
2411c6a0718SPierre Ossman switch (RSP_TYPE(mmc_resp_type(cmd))) {
2421c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
2431c6a0718SPierre Ossman cmdat |= CMDAT_RESP_SHORT;
2441c6a0718SPierre Ossman break;
2451c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R3):
2461c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R3;
2471c6a0718SPierre Ossman break;
2481c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R2):
2491c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R2;
2501c6a0718SPierre Ossman break;
2511c6a0718SPierre Ossman default:
2521c6a0718SPierre Ossman break;
2531c6a0718SPierre Ossman }
2541c6a0718SPierre Ossman
2551c6a0718SPierre Ossman writel(cmd->opcode, host->base + MMC_CMD);
2561c6a0718SPierre Ossman writel(cmd->arg >> 16, host->base + MMC_ARGH);
2571c6a0718SPierre Ossman writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
2581c6a0718SPierre Ossman writel(cmdat, host->base + MMC_CMDAT);
2591c6a0718SPierre Ossman writel(host->clkrt, host->base + MMC_CLKRT);
2601c6a0718SPierre Ossman
2611c6a0718SPierre Ossman writel(START_CLOCK, host->base + MMC_STRPCL);
2621c6a0718SPierre Ossman
2631c6a0718SPierre Ossman pxamci_enable_irq(host, END_CMD_RES);
2641c6a0718SPierre Ossman }
2651c6a0718SPierre Ossman
pxamci_finish_request(struct pxamci_host * host,struct mmc_request * mrq)2661c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
2671c6a0718SPierre Ossman {
2681c6a0718SPierre Ossman host->mrq = NULL;
2691c6a0718SPierre Ossman host->cmd = NULL;
2701c6a0718SPierre Ossman host->data = NULL;
2711c6a0718SPierre Ossman mmc_request_done(host->mmc, mrq);
2721c6a0718SPierre Ossman }
2731c6a0718SPierre Ossman
pxamci_cmd_done(struct pxamci_host * host,unsigned int stat)2741c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
2751c6a0718SPierre Ossman {
2761c6a0718SPierre Ossman struct mmc_command *cmd = host->cmd;
2771c6a0718SPierre Ossman int i;
2781c6a0718SPierre Ossman u32 v;
2791c6a0718SPierre Ossman
2801c6a0718SPierre Ossman if (!cmd)
2811c6a0718SPierre Ossman return 0;
2821c6a0718SPierre Ossman
2831c6a0718SPierre Ossman host->cmd = NULL;
2841c6a0718SPierre Ossman
2851c6a0718SPierre Ossman /*
2861c6a0718SPierre Ossman * Did I mention this is Sick. We always need to
2871c6a0718SPierre Ossman * discard the upper 8 bits of the first 16-bit word.
2881c6a0718SPierre Ossman */
2891c6a0718SPierre Ossman v = readl(host->base + MMC_RES) & 0xffff;
2901c6a0718SPierre Ossman for (i = 0; i < 4; i++) {
2911c6a0718SPierre Ossman u32 w1 = readl(host->base + MMC_RES) & 0xffff;
2921c6a0718SPierre Ossman u32 w2 = readl(host->base + MMC_RES) & 0xffff;
2931c6a0718SPierre Ossman cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
2941c6a0718SPierre Ossman v = w2;
2951c6a0718SPierre Ossman }
2961c6a0718SPierre Ossman
2971c6a0718SPierre Ossman if (stat & STAT_TIME_OUT_RESPONSE) {
29817b0429dSPierre Ossman cmd->error = -ETIMEDOUT;
2991c6a0718SPierre Ossman } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
3001c6a0718SPierre Ossman /*
3011c6a0718SPierre Ossman * workaround for erratum #42:
3021c6a0718SPierre Ossman * Intel PXA27x Family Processor Specification Update Rev 001
30390e07d9fSNicolas Pitre * A bogus CRC error can appear if the msb of a 136 bit
30490e07d9fSNicolas Pitre * response is a one.
3051c6a0718SPierre Ossman */
306e10a854cSCliff Brake if (cpu_is_pxa27x() &&
307e10a854cSCliff Brake (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000))
3081c6a0718SPierre Ossman pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
309e10a854cSCliff Brake else
31017b0429dSPierre Ossman cmd->error = -EILSEQ;
3111c6a0718SPierre Ossman }
3121c6a0718SPierre Ossman
3131c6a0718SPierre Ossman pxamci_disable_irq(host, END_CMD_RES);
31417b0429dSPierre Ossman if (host->data && !cmd->error) {
3151c6a0718SPierre Ossman pxamci_enable_irq(host, DATA_TRAN_DONE);
316b6018958SCliff Brake /*
317b6018958SCliff Brake * workaround for erratum #91, if doing write
318b6018958SCliff Brake * enable DMA late
319b6018958SCliff Brake */
320b6018958SCliff Brake if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
3216464b714SDaniel Mack dma_async_issue_pending(host->dma_chan_tx);
3221c6a0718SPierre Ossman } else {
3231c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq);
3241c6a0718SPierre Ossman }
3251c6a0718SPierre Ossman
3261c6a0718SPierre Ossman return 1;
3271c6a0718SPierre Ossman }
3281c6a0718SPierre Ossman
pxamci_data_done(struct pxamci_host * host,unsigned int stat)3291c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
3301c6a0718SPierre Ossman {
3311c6a0718SPierre Ossman struct mmc_data *data = host->data;
3326464b714SDaniel Mack struct dma_chan *chan;
3331c6a0718SPierre Ossman
3341c6a0718SPierre Ossman if (!data)
3351c6a0718SPierre Ossman return 0;
3361c6a0718SPierre Ossman
3376464b714SDaniel Mack if (data->flags & MMC_DATA_READ)
3386464b714SDaniel Mack chan = host->dma_chan_rx;
3396464b714SDaniel Mack else
3406464b714SDaniel Mack chan = host->dma_chan_tx;
3416464b714SDaniel Mack dma_unmap_sg(chan->device->dev,
3426464b714SDaniel Mack data->sg, data->sg_len, host->dma_dir);
3431c6a0718SPierre Ossman
3441c6a0718SPierre Ossman if (stat & STAT_READ_TIME_OUT)
34517b0429dSPierre Ossman data->error = -ETIMEDOUT;
3461c6a0718SPierre Ossman else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
34717b0429dSPierre Ossman data->error = -EILSEQ;
3481c6a0718SPierre Ossman
3491c6a0718SPierre Ossman /*
3501c6a0718SPierre Ossman * There appears to be a hardware design bug here. There seems to
3511c6a0718SPierre Ossman * be no way to find out how much data was transferred to the card.
3521c6a0718SPierre Ossman * This means that if there was an error on any block, we mark all
3531c6a0718SPierre Ossman * data blocks as being in error.
3541c6a0718SPierre Ossman */
35517b0429dSPierre Ossman if (!data->error)
3561c6a0718SPierre Ossman data->bytes_xfered = data->blocks * data->blksz;
3571c6a0718SPierre Ossman else
3581c6a0718SPierre Ossman data->bytes_xfered = 0;
3591c6a0718SPierre Ossman
3601c6a0718SPierre Ossman pxamci_disable_irq(host, DATA_TRAN_DONE);
3611c6a0718SPierre Ossman
3621c6a0718SPierre Ossman host->data = NULL;
3631c6a0718SPierre Ossman if (host->mrq->stop) {
3641c6a0718SPierre Ossman pxamci_stop_clock(host);
365df456f47SBridge Wu pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
3661c6a0718SPierre Ossman } else {
3671c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq);
3681c6a0718SPierre Ossman }
3691c6a0718SPierre Ossman
3701c6a0718SPierre Ossman return 1;
3711c6a0718SPierre Ossman }
3721c6a0718SPierre Ossman
pxamci_irq(int irq,void * devid)3731c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid)
3741c6a0718SPierre Ossman {
3751c6a0718SPierre Ossman struct pxamci_host *host = devid;
3761c6a0718SPierre Ossman unsigned int ireg;
3771c6a0718SPierre Ossman int handled = 0;
3781c6a0718SPierre Ossman
37981ab570fSBridge Wu ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
3801c6a0718SPierre Ossman
3811c6a0718SPierre Ossman if (ireg) {
3821c6a0718SPierre Ossman unsigned stat = readl(host->base + MMC_STAT);
3831c6a0718SPierre Ossman
3841c6a0718SPierre Ossman pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
3851c6a0718SPierre Ossman
3861c6a0718SPierre Ossman if (ireg & END_CMD_RES)
3871c6a0718SPierre Ossman handled |= pxamci_cmd_done(host, stat);
3881c6a0718SPierre Ossman if (ireg & DATA_TRAN_DONE)
3891c6a0718SPierre Ossman handled |= pxamci_data_done(host, stat);
3905d3ad4e8SBridge Wu if (ireg & SDIO_INT) {
3915d3ad4e8SBridge Wu mmc_signal_sdio_irq(host->mmc);
3925d3ad4e8SBridge Wu handled = 1;
3935d3ad4e8SBridge Wu }
3941c6a0718SPierre Ossman }
3951c6a0718SPierre Ossman
3961c6a0718SPierre Ossman return IRQ_RETVAL(handled);
3971c6a0718SPierre Ossman }
3981c6a0718SPierre Ossman
pxamci_request(struct mmc_host * mmc,struct mmc_request * mrq)3991c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
4001c6a0718SPierre Ossman {
4011c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc);
4021c6a0718SPierre Ossman unsigned int cmdat;
4031c6a0718SPierre Ossman
4041c6a0718SPierre Ossman WARN_ON(host->mrq != NULL);
4051c6a0718SPierre Ossman
4061c6a0718SPierre Ossman host->mrq = mrq;
4071c6a0718SPierre Ossman
4081c6a0718SPierre Ossman pxamci_stop_clock(host);
4091c6a0718SPierre Ossman
4101c6a0718SPierre Ossman cmdat = host->cmdat;
4111c6a0718SPierre Ossman host->cmdat &= ~CMDAT_INIT;
4121c6a0718SPierre Ossman
4131c6a0718SPierre Ossman if (mrq->data) {
4141c6a0718SPierre Ossman pxamci_setup_data(host, mrq->data);
4151c6a0718SPierre Ossman
4161c6a0718SPierre Ossman cmdat &= ~CMDAT_BUSY;
4171c6a0718SPierre Ossman cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
4181c6a0718SPierre Ossman if (mrq->data->flags & MMC_DATA_WRITE)
4191c6a0718SPierre Ossman cmdat |= CMDAT_WRITE;
4201c6a0718SPierre Ossman }
4211c6a0718SPierre Ossman
4221c6a0718SPierre Ossman pxamci_start_cmd(host, mrq->cmd, cmdat);
4231c6a0718SPierre Ossman }
4241c6a0718SPierre Ossman
pxamci_get_ro(struct mmc_host * mmc)4251c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc)
4261c6a0718SPierre Ossman {
4271c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc);
4281c6a0718SPierre Ossman
429c914a27cSLinus Walleij if (host->use_ro_gpio)
430fd546ee6SRobert Jarzmik return mmc_gpio_get_ro(mmc);
4311c6a0718SPierre Ossman if (host->pdata && host->pdata->get_ro)
43208f80bb5SAnton Vorontsov return !!host->pdata->get_ro(mmc_dev(mmc));
43308f80bb5SAnton Vorontsov /*
43408f80bb5SAnton Vorontsov * Board doesn't support read only detection; let the mmc core
43508f80bb5SAnton Vorontsov * decide what to do.
43608f80bb5SAnton Vorontsov */
43708f80bb5SAnton Vorontsov return -ENOSYS;
4381c6a0718SPierre Ossman }
4391c6a0718SPierre Ossman
pxamci_set_ios(struct mmc_host * mmc,struct mmc_ios * ios)4401c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
4411c6a0718SPierre Ossman {
4421c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc);
4431c6a0718SPierre Ossman
4441c6a0718SPierre Ossman if (ios->clock) {
445ebebd9b0SRussell King unsigned long rate = host->clkrate;
446ebebd9b0SRussell King unsigned int clk = rate / ios->clock;
447ebebd9b0SRussell King
448d8cb70d1SRussell King if (host->clkrt == CLKRT_OFF)
449e7370819SRobert Jarzmik clk_prepare_enable(host->clk);
450d8cb70d1SRussell King
45164eb036aSBridge Wu if (ios->clock == 26000000) {
452fa3f9938SHaojian Zhuang /* to support 26MHz */
45364eb036aSBridge Wu host->clkrt = 7;
45464eb036aSBridge Wu } else {
45564eb036aSBridge Wu /* to handle (19.5MHz, 26MHz) */
45664eb036aSBridge Wu if (!clk)
45764eb036aSBridge Wu clk = 1;
45864eb036aSBridge Wu
459ebebd9b0SRussell King /*
460ebebd9b0SRussell King * clk might result in a lower divisor than we
461ebebd9b0SRussell King * desire. check for that condition and adjust
462ebebd9b0SRussell King * as appropriate.
463ebebd9b0SRussell King */
464ebebd9b0SRussell King if (rate / clk > ios->clock)
4651c6a0718SPierre Ossman clk <<= 1;
4661c6a0718SPierre Ossman host->clkrt = fls(clk) - 1;
46764eb036aSBridge Wu }
4681c6a0718SPierre Ossman
4691c6a0718SPierre Ossman /*
4701c6a0718SPierre Ossman * we write clkrt on the next command
4711c6a0718SPierre Ossman */
4721c6a0718SPierre Ossman } else {
4731c6a0718SPierre Ossman pxamci_stop_clock(host);
474d8cb70d1SRussell King if (host->clkrt != CLKRT_OFF) {
475d8cb70d1SRussell King host->clkrt = CLKRT_OFF;
476e7370819SRobert Jarzmik clk_disable_unprepare(host->clk);
4771c6a0718SPierre Ossman }
478d8cb70d1SRussell King }
4791c6a0718SPierre Ossman
4801c6a0718SPierre Ossman if (host->power_mode != ios->power_mode) {
48199fc5131SLinus Walleij int ret;
48299fc5131SLinus Walleij
4831c6a0718SPierre Ossman host->power_mode = ios->power_mode;
4841c6a0718SPierre Ossman
48599fc5131SLinus Walleij ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
48699fc5131SLinus Walleij if (ret) {
48799fc5131SLinus Walleij dev_err(mmc_dev(mmc), "unable to set power\n");
48899fc5131SLinus Walleij /*
48999fc5131SLinus Walleij * The .set_ios() function in the mmc_host_ops
49099fc5131SLinus Walleij * struct return void, and failing to set the
49199fc5131SLinus Walleij * power should be rare so we print an error and
49299fc5131SLinus Walleij * return here.
49399fc5131SLinus Walleij */
49499fc5131SLinus Walleij return;
49599fc5131SLinus Walleij }
4961c6a0718SPierre Ossman
4971c6a0718SPierre Ossman if (ios->power_mode == MMC_POWER_ON)
4981c6a0718SPierre Ossman host->cmdat |= CMDAT_INIT;
4991c6a0718SPierre Ossman }
5001c6a0718SPierre Ossman
501df456f47SBridge Wu if (ios->bus_width == MMC_BUS_WIDTH_4)
502df456f47SBridge Wu host->cmdat |= CMDAT_SD_4DAT;
503df456f47SBridge Wu else
504df456f47SBridge Wu host->cmdat &= ~CMDAT_SD_4DAT;
505df456f47SBridge Wu
50699fc5131SLinus Walleij dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
5071c6a0718SPierre Ossman host->clkrt, host->cmdat);
5081c6a0718SPierre Ossman }
5091c6a0718SPierre Ossman
pxamci_enable_sdio_irq(struct mmc_host * host,int enable)5105d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
5115d3ad4e8SBridge Wu {
5125d3ad4e8SBridge Wu struct pxamci_host *pxa_host = mmc_priv(host);
5135d3ad4e8SBridge Wu
5145d3ad4e8SBridge Wu if (enable)
5155d3ad4e8SBridge Wu pxamci_enable_irq(pxa_host, SDIO_INT);
5165d3ad4e8SBridge Wu else
5175d3ad4e8SBridge Wu pxamci_disable_irq(pxa_host, SDIO_INT);
5185d3ad4e8SBridge Wu }
5195d3ad4e8SBridge Wu
5201c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = {
5211c6a0718SPierre Ossman .request = pxamci_request,
522fd546ee6SRobert Jarzmik .get_cd = mmc_gpio_get_cd,
5231c6a0718SPierre Ossman .get_ro = pxamci_get_ro,
5241c6a0718SPierre Ossman .set_ios = pxamci_set_ios,
5255d3ad4e8SBridge Wu .enable_sdio_irq = pxamci_enable_sdio_irq,
5261c6a0718SPierre Ossman };
5271c6a0718SPierre Ossman
pxamci_dma_irq(void * param)5286464b714SDaniel Mack static void pxamci_dma_irq(void *param)
5291c6a0718SPierre Ossman {
5306464b714SDaniel Mack struct pxamci_host *host = param;
5316464b714SDaniel Mack struct dma_tx_state state;
5326464b714SDaniel Mack enum dma_status status;
5336464b714SDaniel Mack struct dma_chan *chan;
5346464b714SDaniel Mack unsigned long flags;
535c783837bSNicolas Pitre
5366464b714SDaniel Mack spin_lock_irqsave(&host->lock, flags);
5376464b714SDaniel Mack
5386464b714SDaniel Mack if (!host->data)
5396464b714SDaniel Mack goto out_unlock;
5406464b714SDaniel Mack
5416464b714SDaniel Mack if (host->data->flags & MMC_DATA_READ)
5426464b714SDaniel Mack chan = host->dma_chan_rx;
5436464b714SDaniel Mack else
5446464b714SDaniel Mack chan = host->dma_chan_tx;
5456464b714SDaniel Mack
5466464b714SDaniel Mack status = dmaengine_tx_status(chan, host->dma_cookie, &state);
5476464b714SDaniel Mack
5486464b714SDaniel Mack if (likely(status == DMA_COMPLETE)) {
549c783837bSNicolas Pitre writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
550c783837bSNicolas Pitre } else {
5516464b714SDaniel Mack pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
5526464b714SDaniel Mack host->data->flags & MMC_DATA_READ ? "rx" : "tx");
553c783837bSNicolas Pitre host->data->error = -EIO;
554c783837bSNicolas Pitre pxamci_data_done(host, 0);
555c783837bSNicolas Pitre }
5566464b714SDaniel Mack
5576464b714SDaniel Mack out_unlock:
5586464b714SDaniel Mack spin_unlock_irqrestore(&host->lock, flags);
5591c6a0718SPierre Ossman }
5601c6a0718SPierre Ossman
pxamci_detect_irq(int irq,void * devid)5611c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid)
5621c6a0718SPierre Ossman {
5631c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(devid);
5641c6a0718SPierre Ossman
56538a8dda9SDaniel Mack mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms));
5661c6a0718SPierre Ossman return IRQ_HANDLED;
5671c6a0718SPierre Ossman }
5681c6a0718SPierre Ossman
569e6027b46SDaniel Mack #ifdef CONFIG_OF
570e6027b46SDaniel Mack static const struct of_device_id pxa_mmc_dt_ids[] = {
571e6027b46SDaniel Mack { .compatible = "marvell,pxa-mmc" },
572e6027b46SDaniel Mack { }
573e6027b46SDaniel Mack };
574e6027b46SDaniel Mack
575e6027b46SDaniel Mack MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
576e6027b46SDaniel Mack
pxamci_of_init(struct platform_device * pdev,struct mmc_host * mmc)577fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev,
578fa3a5115SDaniel Mack struct mmc_host *mmc)
579e6027b46SDaniel Mack {
580e6027b46SDaniel Mack struct device_node *np = pdev->dev.of_node;
58138a8dda9SDaniel Mack struct pxamci_host *host = mmc_priv(mmc);
582e6027b46SDaniel Mack u32 tmp;
583fa3a5115SDaniel Mack int ret;
584e6027b46SDaniel Mack
585e6027b46SDaniel Mack if (!np)
586e6027b46SDaniel Mack return 0;
587e6027b46SDaniel Mack
588e6027b46SDaniel Mack /* pxa-mmc specific */
589e6027b46SDaniel Mack if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
59038a8dda9SDaniel Mack host->detect_delay_ms = tmp;
591e6027b46SDaniel Mack
592fa3a5115SDaniel Mack ret = mmc_of_parse(mmc);
593fa3a5115SDaniel Mack if (ret < 0)
594fa3a5115SDaniel Mack return ret;
595fa3a5115SDaniel Mack
596e6027b46SDaniel Mack return 0;
597e6027b46SDaniel Mack }
598e6027b46SDaniel Mack #else
pxamci_of_init(struct platform_device * pdev,struct mmc_host * mmc)599fa3a5115SDaniel Mack static int pxamci_of_init(struct platform_device *pdev,
600fa3a5115SDaniel Mack struct mmc_host *mmc)
601e6027b46SDaniel Mack {
602e6027b46SDaniel Mack return 0;
603e6027b46SDaniel Mack }
604e6027b46SDaniel Mack #endif
605e6027b46SDaniel Mack
pxamci_probe(struct platform_device * pdev)6061c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev)
6071c6a0718SPierre Ossman {
6081c6a0718SPierre Ossman struct mmc_host *mmc;
6091c6a0718SPierre Ossman struct pxamci_host *host = NULL;
61023f3ff72SDaniel Mack struct device *dev = &pdev->dev;
6116b3348f9SRobert Jarzmik struct resource *r;
61238a8dda9SDaniel Mack int ret, irq;
6131c6a0718SPierre Ossman
6141c6a0718SPierre Ossman irq = platform_get_irq(pdev, 0);
61507e7716cSRobert Jarzmik if (irq < 0)
61607e7716cSRobert Jarzmik return irq;
6171c6a0718SPierre Ossman
61823f3ff72SDaniel Mack mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev);
6191c6a0718SPierre Ossman if (!mmc) {
6201c6a0718SPierre Ossman ret = -ENOMEM;
6211c6a0718SPierre Ossman goto out;
6221c6a0718SPierre Ossman }
6231c6a0718SPierre Ossman
6241c6a0718SPierre Ossman mmc->ops = &pxamci_ops;
6251c6a0718SPierre Ossman
6261c6a0718SPierre Ossman /*
6271c6a0718SPierre Ossman * We can do SG-DMA, but we don't because we never know how much
6281c6a0718SPierre Ossman * data we successfully wrote to the card.
6291c6a0718SPierre Ossman */
630a36274e0SMartin K. Petersen mmc->max_segs = NR_SG;
6311c6a0718SPierre Ossman
6321c6a0718SPierre Ossman /*
6331c6a0718SPierre Ossman * Our hardware DMA can handle a maximum of one page per SG entry.
6341c6a0718SPierre Ossman */
6351c6a0718SPierre Ossman mmc->max_seg_size = PAGE_SIZE;
6361c6a0718SPierre Ossman
6371c6a0718SPierre Ossman /*
638fe2dc44eSNicolas Pitre * Block length register is only 10 bits before PXA27x.
6391c6a0718SPierre Ossman */
6400ffcbfd5SEric Miao mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048;
6411c6a0718SPierre Ossman
6421c6a0718SPierre Ossman /*
6431c6a0718SPierre Ossman * Block count register is 16 bits.
6441c6a0718SPierre Ossman */
6451c6a0718SPierre Ossman mmc->max_blk_count = 65535;
6461c6a0718SPierre Ossman
647fa3a5115SDaniel Mack ret = pxamci_of_init(pdev, mmc);
648fa3a5115SDaniel Mack if (ret)
64998d7c5e5SChristophe JAILLET goto out;
650fa3a5115SDaniel Mack
6511c6a0718SPierre Ossman host = mmc_priv(mmc);
6521c6a0718SPierre Ossman host->mmc = mmc;
6531c6a0718SPierre Ossman host->pdata = pdev->dev.platform_data;
654d8cb70d1SRussell King host->clkrt = CLKRT_OFF;
655ebebd9b0SRussell King
65623f3ff72SDaniel Mack host->clk = devm_clk_get(dev, NULL);
657ebebd9b0SRussell King if (IS_ERR(host->clk)) {
658ebebd9b0SRussell King ret = PTR_ERR(host->clk);
659ebebd9b0SRussell King host->clk = NULL;
660ebebd9b0SRussell King goto out;
661ebebd9b0SRussell King }
662ebebd9b0SRussell King
663ebebd9b0SRussell King host->clkrate = clk_get_rate(host->clk);
664ebebd9b0SRussell King
665ebebd9b0SRussell King /*
666ebebd9b0SRussell King * Calculate minimum clock rate, rounding up.
667ebebd9b0SRussell King */
668ebebd9b0SRussell King mmc->f_min = (host->clkrate + 63) / 64;
669fa3f9938SHaojian Zhuang mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
670ebebd9b0SRussell King
67161951fd6SDaniel Mack ret = pxamci_init_ocr(host);
67261951fd6SDaniel Mack if (ret < 0)
673b886f54cSChristophe JAILLET goto out;
6748385f9cbSDaniel Ribeiro
675de3ee99bSLinus Walleij mmc->caps = 0;
6765d3ad4e8SBridge Wu host->cmdat = 0;
6770ffcbfd5SEric Miao if (!cpu_is_pxa25x()) {
6785d3ad4e8SBridge Wu mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
6795d3ad4e8SBridge Wu host->cmdat |= CMDAT_SDIO_INT_EN;
680fa3f9938SHaojian Zhuang if (mmc_has_26MHz())
68164eb036aSBridge Wu mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
68264eb036aSBridge Wu MMC_CAP_SD_HIGHSPEED;
6835d3ad4e8SBridge Wu }
6841c6a0718SPierre Ossman
6851c6a0718SPierre Ossman spin_lock_init(&host->lock);
6861c6a0718SPierre Ossman host->imask = MMC_I_MASK_ALL;
6871c6a0718SPierre Ossman
688c89a869bSYangtao Li host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
68907e7716cSRobert Jarzmik if (IS_ERR(host->base)) {
69007e7716cSRobert Jarzmik ret = PTR_ERR(host->base);
6911c6a0718SPierre Ossman goto out;
6921c6a0718SPierre Ossman }
693c89a869bSYangtao Li host->res = r;
6941c6a0718SPierre Ossman
6951c6a0718SPierre Ossman /*
6961c6a0718SPierre Ossman * Ensure that the host controller is shut down, and setup
6971c6a0718SPierre Ossman * with our defaults.
6981c6a0718SPierre Ossman */
6991c6a0718SPierre Ossman pxamci_stop_clock(host);
7001c6a0718SPierre Ossman writel(0, host->base + MMC_SPI);
7011c6a0718SPierre Ossman writel(64, host->base + MMC_RESTO);
7021c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK);
7031c6a0718SPierre Ossman
70423f3ff72SDaniel Mack ret = devm_request_irq(dev, irq, pxamci_irq, 0,
70507e7716cSRobert Jarzmik DRIVER_NAME, host);
7061c6a0718SPierre Ossman if (ret)
7071c6a0718SPierre Ossman goto out;
7081c6a0718SPierre Ossman
7091c6a0718SPierre Ossman platform_set_drvdata(pdev, mmc);
7101c6a0718SPierre Ossman
711e1ebb456SPeter Ujfalusi host->dma_chan_rx = dma_request_chan(dev, "rx");
712e1ebb456SPeter Ujfalusi if (IS_ERR(host->dma_chan_rx)) {
71323f3ff72SDaniel Mack dev_err(dev, "unable to request rx dma channel\n");
714e1ebb456SPeter Ujfalusi ret = PTR_ERR(host->dma_chan_rx);
715e1ebb456SPeter Ujfalusi host->dma_chan_rx = NULL;
7166464b714SDaniel Mack goto out;
7176464b714SDaniel Mack }
7186464b714SDaniel Mack
719e1ebb456SPeter Ujfalusi host->dma_chan_tx = dma_request_chan(dev, "tx");
720e1ebb456SPeter Ujfalusi if (IS_ERR(host->dma_chan_tx)) {
72123f3ff72SDaniel Mack dev_err(dev, "unable to request tx dma channel\n");
722e1ebb456SPeter Ujfalusi ret = PTR_ERR(host->dma_chan_tx);
723e1ebb456SPeter Ujfalusi host->dma_chan_tx = NULL;
7246464b714SDaniel Mack goto out;
7256464b714SDaniel Mack }
7269a788c6bSBridge Wu
727b405db6cSRobert Jarzmik if (host->pdata) {
72838a8dda9SDaniel Mack host->detect_delay_ms = host->pdata->detect_delay_ms;
72938a8dda9SDaniel Mack
730f54005b5SLinus Walleij host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
731f54005b5SLinus Walleij if (IS_ERR(host->power)) {
732d7b819b5SZhihao Cheng ret = PTR_ERR(host->power);
733f54005b5SLinus Walleij dev_err(dev, "Failed requesting gpio_power\n");
734b405db6cSRobert Jarzmik goto out;
735b405db6cSRobert Jarzmik }
73638a8dda9SDaniel Mack
737c914a27cSLinus Walleij /* FIXME: should we pass detection delay to debounce? */
738d0052ad9SMichał Mirosław ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0);
739c914a27cSLinus Walleij if (ret && ret != -ENOENT) {
740c914a27cSLinus Walleij dev_err(dev, "Failed requesting gpio_cd\n");
741c914a27cSLinus Walleij goto out;
742c914a27cSLinus Walleij }
743c914a27cSLinus Walleij
7449073d10bSMichał Mirosław if (!host->pdata->gpio_card_ro_invert)
7459073d10bSMichał Mirosław mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
7469073d10bSMichał Mirosław
747d0052ad9SMichał Mirosław ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0);
748c914a27cSLinus Walleij if (ret && ret != -ENOENT) {
749c914a27cSLinus Walleij dev_err(dev, "Failed requesting gpio_ro\n");
750c914a27cSLinus Walleij goto out;
751c914a27cSLinus Walleij }
7529073d10bSMichał Mirosław if (!ret)
753c914a27cSLinus Walleij host->use_ro_gpio = true;
754b405db6cSRobert Jarzmik
75538a8dda9SDaniel Mack if (host->pdata->init)
75623f3ff72SDaniel Mack host->pdata->init(dev, pxamci_detect_irq, mmc);
7571c6a0718SPierre Ossman
758f54005b5SLinus Walleij if (host->power && host->pdata->setpower)
75923f3ff72SDaniel Mack dev_warn(dev, "gpio_power and setpower() both defined\n");
760c914a27cSLinus Walleij if (host->use_ro_gpio && host->pdata->get_ro)
76123f3ff72SDaniel Mack dev_warn(dev, "gpio_ro and get_ro() both defined\n");
76238a8dda9SDaniel Mack }
763b405db6cSRobert Jarzmik
76480e1ef3aSYang Yingliang ret = mmc_add_host(mmc);
76580e1ef3aSYang Yingliang if (ret) {
76680e1ef3aSYang Yingliang if (host->pdata && host->pdata->exit)
76780e1ef3aSYang Yingliang host->pdata->exit(dev, mmc);
76880e1ef3aSYang Yingliang goto out;
76980e1ef3aSYang Yingliang }
7701c6a0718SPierre Ossman
7711c6a0718SPierre Ossman return 0;
7721c6a0718SPierre Ossman
7731c6a0718SPierre Ossman out:
7741c6a0718SPierre Ossman if (host) {
7756464b714SDaniel Mack if (host->dma_chan_rx)
7766464b714SDaniel Mack dma_release_channel(host->dma_chan_rx);
7776464b714SDaniel Mack if (host->dma_chan_tx)
7786464b714SDaniel Mack dma_release_channel(host->dma_chan_tx);
7791c6a0718SPierre Ossman }
7801c6a0718SPierre Ossman if (mmc)
7811c6a0718SPierre Ossman mmc_free_host(mmc);
7821c6a0718SPierre Ossman return ret;
7831c6a0718SPierre Ossman }
7841c6a0718SPierre Ossman
pxamci_remove(struct platform_device * pdev)785*fac44eb8SYangtao Li static void pxamci_remove(struct platform_device *pdev)
7861c6a0718SPierre Ossman {
7871c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(pdev);
7881c6a0718SPierre Ossman
7891c6a0718SPierre Ossman if (mmc) {
7901c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc);
7911c6a0718SPierre Ossman
7925d6b1edfSDaniel Mack mmc_remove_host(mmc);
7935d6b1edfSDaniel Mack
7941c6a0718SPierre Ossman if (host->pdata && host->pdata->exit)
7951c6a0718SPierre Ossman host->pdata->exit(&pdev->dev, mmc);
7961c6a0718SPierre Ossman
7971c6a0718SPierre Ossman pxamci_stop_clock(host);
7981c6a0718SPierre Ossman writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
7991c6a0718SPierre Ossman END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
8001c6a0718SPierre Ossman host->base + MMC_I_MASK);
8011c6a0718SPierre Ossman
8026464b714SDaniel Mack dmaengine_terminate_all(host->dma_chan_rx);
8036464b714SDaniel Mack dmaengine_terminate_all(host->dma_chan_tx);
8046464b714SDaniel Mack dma_release_channel(host->dma_chan_rx);
8056464b714SDaniel Mack dma_release_channel(host->dma_chan_tx);
8061c6a0718SPierre Ossman
8071c6a0718SPierre Ossman mmc_free_host(mmc);
8081c6a0718SPierre Ossman }
8091c6a0718SPierre Ossman }
8101c6a0718SPierre Ossman
8111c6a0718SPierre Ossman static struct platform_driver pxamci_driver = {
8121c6a0718SPierre Ossman .probe = pxamci_probe,
813*fac44eb8SYangtao Li .remove_new = pxamci_remove,
8141c6a0718SPierre Ossman .driver = {
8151c6a0718SPierre Ossman .name = DRIVER_NAME,
81621b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS,
817e6027b46SDaniel Mack .of_match_table = of_match_ptr(pxa_mmc_dt_ids),
8181c6a0718SPierre Ossman },
8191c6a0718SPierre Ossman };
8201c6a0718SPierre Ossman
821d1f81a64SAxel Lin module_platform_driver(pxamci_driver);
8221c6a0718SPierre Ossman
8231c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
8241c6a0718SPierre Ossman MODULE_LICENSE("GPL");
825bc65c724SKay Sievers MODULE_ALIAS("platform:pxa2xx-mci");
826