11c6a0718SPierre Ossman /* 270f10482SPierre Ossman * linux/drivers/mmc/host/pxa.c - PXA MMCI driver 31c6a0718SPierre Ossman * 41c6a0718SPierre Ossman * Copyright (C) 2003 Russell King, All Rights Reserved. 51c6a0718SPierre Ossman * 61c6a0718SPierre Ossman * This program is free software; you can redistribute it and/or modify 71c6a0718SPierre Ossman * it under the terms of the GNU General Public License version 2 as 81c6a0718SPierre Ossman * published by the Free Software Foundation. 91c6a0718SPierre Ossman * 101c6a0718SPierre Ossman * This hardware is really sick: 111c6a0718SPierre Ossman * - No way to clear interrupts. 121c6a0718SPierre Ossman * - Have to turn off the clock whenever we touch the device. 131c6a0718SPierre Ossman * - Doesn't tell you how many data blocks were transferred. 141c6a0718SPierre Ossman * Yuck! 151c6a0718SPierre Ossman * 161c6a0718SPierre Ossman * 1 and 3 byte data transfers not supported 171c6a0718SPierre Ossman * max block length up to 1023 181c6a0718SPierre Ossman */ 191c6a0718SPierre Ossman #include <linux/module.h> 201c6a0718SPierre Ossman #include <linux/init.h> 211c6a0718SPierre Ossman #include <linux/ioport.h> 221c6a0718SPierre Ossman #include <linux/platform_device.h> 231c6a0718SPierre Ossman #include <linux/delay.h> 241c6a0718SPierre Ossman #include <linux/interrupt.h> 251c6a0718SPierre Ossman #include <linux/dma-mapping.h> 26ebebd9b0SRussell King #include <linux/clk.h> 27ebebd9b0SRussell King #include <linux/err.h> 281c6a0718SPierre Ossman #include <linux/mmc/host.h> 291c6a0718SPierre Ossman 301c6a0718SPierre Ossman #include <asm/dma.h> 311c6a0718SPierre Ossman #include <asm/io.h> 321c6a0718SPierre Ossman #include <asm/sizes.h> 331c6a0718SPierre Ossman 341c6a0718SPierre Ossman #include <asm/arch/pxa-regs.h> 351c6a0718SPierre Ossman #include <asm/arch/mmc.h> 361c6a0718SPierre Ossman 371c6a0718SPierre Ossman #include "pxamci.h" 381c6a0718SPierre Ossman 391c6a0718SPierre Ossman #define DRIVER_NAME "pxa2xx-mci" 401c6a0718SPierre Ossman 411c6a0718SPierre Ossman #define NR_SG 1 42d8cb70d1SRussell King #define CLKRT_OFF (~0) 431c6a0718SPierre Ossman 441c6a0718SPierre Ossman struct pxamci_host { 451c6a0718SPierre Ossman struct mmc_host *mmc; 461c6a0718SPierre Ossman spinlock_t lock; 471c6a0718SPierre Ossman struct resource *res; 481c6a0718SPierre Ossman void __iomem *base; 49ebebd9b0SRussell King struct clk *clk; 50ebebd9b0SRussell King unsigned long clkrate; 511c6a0718SPierre Ossman int irq; 521c6a0718SPierre Ossman int dma; 531c6a0718SPierre Ossman unsigned int clkrt; 541c6a0718SPierre Ossman unsigned int cmdat; 551c6a0718SPierre Ossman unsigned int imask; 561c6a0718SPierre Ossman unsigned int power_mode; 571c6a0718SPierre Ossman struct pxamci_platform_data *pdata; 581c6a0718SPierre Ossman 591c6a0718SPierre Ossman struct mmc_request *mrq; 601c6a0718SPierre Ossman struct mmc_command *cmd; 611c6a0718SPierre Ossman struct mmc_data *data; 621c6a0718SPierre Ossman 631c6a0718SPierre Ossman dma_addr_t sg_dma; 641c6a0718SPierre Ossman struct pxa_dma_desc *sg_cpu; 651c6a0718SPierre Ossman unsigned int dma_len; 661c6a0718SPierre Ossman 671c6a0718SPierre Ossman unsigned int dma_dir; 681c6a0718SPierre Ossman }; 691c6a0718SPierre Ossman 701c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host) 711c6a0718SPierre Ossman { 721c6a0718SPierre Ossman if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { 731c6a0718SPierre Ossman unsigned long timeout = 10000; 741c6a0718SPierre Ossman unsigned int v; 751c6a0718SPierre Ossman 761c6a0718SPierre Ossman writel(STOP_CLOCK, host->base + MMC_STRPCL); 771c6a0718SPierre Ossman 781c6a0718SPierre Ossman do { 791c6a0718SPierre Ossman v = readl(host->base + MMC_STAT); 801c6a0718SPierre Ossman if (!(v & STAT_CLK_EN)) 811c6a0718SPierre Ossman break; 821c6a0718SPierre Ossman udelay(1); 831c6a0718SPierre Ossman } while (timeout--); 841c6a0718SPierre Ossman 851c6a0718SPierre Ossman if (v & STAT_CLK_EN) 861c6a0718SPierre Ossman dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); 871c6a0718SPierre Ossman } 881c6a0718SPierre Ossman } 891c6a0718SPierre Ossman 901c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) 911c6a0718SPierre Ossman { 921c6a0718SPierre Ossman unsigned long flags; 931c6a0718SPierre Ossman 941c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags); 951c6a0718SPierre Ossman host->imask &= ~mask; 961c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 971c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags); 981c6a0718SPierre Ossman } 991c6a0718SPierre Ossman 1001c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) 1011c6a0718SPierre Ossman { 1021c6a0718SPierre Ossman unsigned long flags; 1031c6a0718SPierre Ossman 1041c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags); 1051c6a0718SPierre Ossman host->imask |= mask; 1061c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 1071c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1081c6a0718SPierre Ossman } 1091c6a0718SPierre Ossman 1101c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) 1111c6a0718SPierre Ossman { 1121c6a0718SPierre Ossman unsigned int nob = data->blocks; 1131c6a0718SPierre Ossman unsigned long long clks; 1141c6a0718SPierre Ossman unsigned int timeout; 1151c6a0718SPierre Ossman u32 dcmd; 1161c6a0718SPierre Ossman int i; 1171c6a0718SPierre Ossman 1181c6a0718SPierre Ossman host->data = data; 1191c6a0718SPierre Ossman 1201c6a0718SPierre Ossman if (data->flags & MMC_DATA_STREAM) 1211c6a0718SPierre Ossman nob = 0xffff; 1221c6a0718SPierre Ossman 1231c6a0718SPierre Ossman writel(nob, host->base + MMC_NOB); 1241c6a0718SPierre Ossman writel(data->blksz, host->base + MMC_BLKLEN); 1251c6a0718SPierre Ossman 126ebebd9b0SRussell King clks = (unsigned long long)data->timeout_ns * host->clkrate; 1271c6a0718SPierre Ossman do_div(clks, 1000000000UL); 1281c6a0718SPierre Ossman timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); 1291c6a0718SPierre Ossman writel((timeout + 255) / 256, host->base + MMC_RDTO); 1301c6a0718SPierre Ossman 1311c6a0718SPierre Ossman if (data->flags & MMC_DATA_READ) { 1321c6a0718SPierre Ossman host->dma_dir = DMA_FROM_DEVICE; 1331c6a0718SPierre Ossman dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; 1341c6a0718SPierre Ossman DRCMRTXMMC = 0; 1351c6a0718SPierre Ossman DRCMRRXMMC = host->dma | DRCMR_MAPVLD; 1361c6a0718SPierre Ossman } else { 1371c6a0718SPierre Ossman host->dma_dir = DMA_TO_DEVICE; 1381c6a0718SPierre Ossman dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; 1391c6a0718SPierre Ossman DRCMRRXMMC = 0; 1401c6a0718SPierre Ossman DRCMRTXMMC = host->dma | DRCMR_MAPVLD; 1411c6a0718SPierre Ossman } 1421c6a0718SPierre Ossman 1431c6a0718SPierre Ossman dcmd |= DCMD_BURST32 | DCMD_WIDTH1; 1441c6a0718SPierre Ossman 1451c6a0718SPierre Ossman host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 1461c6a0718SPierre Ossman host->dma_dir); 1471c6a0718SPierre Ossman 1481c6a0718SPierre Ossman for (i = 0; i < host->dma_len; i++) { 149c783837bSNicolas Pitre unsigned int length = sg_dma_len(&data->sg[i]); 150c783837bSNicolas Pitre host->sg_cpu[i].dcmd = dcmd | length; 151c783837bSNicolas Pitre if (length & 31 && !(data->flags & MMC_DATA_READ)) 152c783837bSNicolas Pitre host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; 1531c6a0718SPierre Ossman if (data->flags & MMC_DATA_READ) { 1541c6a0718SPierre Ossman host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; 1551c6a0718SPierre Ossman host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); 1561c6a0718SPierre Ossman } else { 1571c6a0718SPierre Ossman host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); 1581c6a0718SPierre Ossman host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; 1591c6a0718SPierre Ossman } 1601c6a0718SPierre Ossman host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * 1611c6a0718SPierre Ossman sizeof(struct pxa_dma_desc); 1621c6a0718SPierre Ossman } 1631c6a0718SPierre Ossman host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; 1641c6a0718SPierre Ossman wmb(); 1651c6a0718SPierre Ossman 1661c6a0718SPierre Ossman DDADR(host->dma) = host->sg_dma; 1671c6a0718SPierre Ossman DCSR(host->dma) = DCSR_RUN; 1681c6a0718SPierre Ossman } 1691c6a0718SPierre Ossman 1701c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) 1711c6a0718SPierre Ossman { 1721c6a0718SPierre Ossman WARN_ON(host->cmd != NULL); 1731c6a0718SPierre Ossman host->cmd = cmd; 1741c6a0718SPierre Ossman 1751c6a0718SPierre Ossman if (cmd->flags & MMC_RSP_BUSY) 1761c6a0718SPierre Ossman cmdat |= CMDAT_BUSY; 1771c6a0718SPierre Ossman 1781c6a0718SPierre Ossman #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) 1791c6a0718SPierre Ossman switch (RSP_TYPE(mmc_resp_type(cmd))) { 1801c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ 1811c6a0718SPierre Ossman cmdat |= CMDAT_RESP_SHORT; 1821c6a0718SPierre Ossman break; 1831c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R3): 1841c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R3; 1851c6a0718SPierre Ossman break; 1861c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R2): 1871c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R2; 1881c6a0718SPierre Ossman break; 1891c6a0718SPierre Ossman default: 1901c6a0718SPierre Ossman break; 1911c6a0718SPierre Ossman } 1921c6a0718SPierre Ossman 1931c6a0718SPierre Ossman writel(cmd->opcode, host->base + MMC_CMD); 1941c6a0718SPierre Ossman writel(cmd->arg >> 16, host->base + MMC_ARGH); 1951c6a0718SPierre Ossman writel(cmd->arg & 0xffff, host->base + MMC_ARGL); 1961c6a0718SPierre Ossman writel(cmdat, host->base + MMC_CMDAT); 1971c6a0718SPierre Ossman writel(host->clkrt, host->base + MMC_CLKRT); 1981c6a0718SPierre Ossman 1991c6a0718SPierre Ossman writel(START_CLOCK, host->base + MMC_STRPCL); 2001c6a0718SPierre Ossman 2011c6a0718SPierre Ossman pxamci_enable_irq(host, END_CMD_RES); 2021c6a0718SPierre Ossman } 2031c6a0718SPierre Ossman 2041c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) 2051c6a0718SPierre Ossman { 2061c6a0718SPierre Ossman host->mrq = NULL; 2071c6a0718SPierre Ossman host->cmd = NULL; 2081c6a0718SPierre Ossman host->data = NULL; 2091c6a0718SPierre Ossman mmc_request_done(host->mmc, mrq); 2101c6a0718SPierre Ossman } 2111c6a0718SPierre Ossman 2121c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) 2131c6a0718SPierre Ossman { 2141c6a0718SPierre Ossman struct mmc_command *cmd = host->cmd; 2151c6a0718SPierre Ossman int i; 2161c6a0718SPierre Ossman u32 v; 2171c6a0718SPierre Ossman 2181c6a0718SPierre Ossman if (!cmd) 2191c6a0718SPierre Ossman return 0; 2201c6a0718SPierre Ossman 2211c6a0718SPierre Ossman host->cmd = NULL; 2221c6a0718SPierre Ossman 2231c6a0718SPierre Ossman /* 2241c6a0718SPierre Ossman * Did I mention this is Sick. We always need to 2251c6a0718SPierre Ossman * discard the upper 8 bits of the first 16-bit word. 2261c6a0718SPierre Ossman */ 2271c6a0718SPierre Ossman v = readl(host->base + MMC_RES) & 0xffff; 2281c6a0718SPierre Ossman for (i = 0; i < 4; i++) { 2291c6a0718SPierre Ossman u32 w1 = readl(host->base + MMC_RES) & 0xffff; 2301c6a0718SPierre Ossman u32 w2 = readl(host->base + MMC_RES) & 0xffff; 2311c6a0718SPierre Ossman cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; 2321c6a0718SPierre Ossman v = w2; 2331c6a0718SPierre Ossman } 2341c6a0718SPierre Ossman 2351c6a0718SPierre Ossman if (stat & STAT_TIME_OUT_RESPONSE) { 23617b0429dSPierre Ossman cmd->error = -ETIMEDOUT; 2371c6a0718SPierre Ossman } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { 2381c6a0718SPierre Ossman #ifdef CONFIG_PXA27x 2391c6a0718SPierre Ossman /* 2401c6a0718SPierre Ossman * workaround for erratum #42: 2411c6a0718SPierre Ossman * Intel PXA27x Family Processor Specification Update Rev 001 24290e07d9fSNicolas Pitre * A bogus CRC error can appear if the msb of a 136 bit 24390e07d9fSNicolas Pitre * response is a one. 2441c6a0718SPierre Ossman */ 24590e07d9fSNicolas Pitre if (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000) { 2461c6a0718SPierre Ossman pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); 24790e07d9fSNicolas Pitre } else 2481c6a0718SPierre Ossman #endif 24917b0429dSPierre Ossman cmd->error = -EILSEQ; 2501c6a0718SPierre Ossman } 2511c6a0718SPierre Ossman 2521c6a0718SPierre Ossman pxamci_disable_irq(host, END_CMD_RES); 25317b0429dSPierre Ossman if (host->data && !cmd->error) { 2541c6a0718SPierre Ossman pxamci_enable_irq(host, DATA_TRAN_DONE); 2551c6a0718SPierre Ossman } else { 2561c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq); 2571c6a0718SPierre Ossman } 2581c6a0718SPierre Ossman 2591c6a0718SPierre Ossman return 1; 2601c6a0718SPierre Ossman } 2611c6a0718SPierre Ossman 2621c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) 2631c6a0718SPierre Ossman { 2641c6a0718SPierre Ossman struct mmc_data *data = host->data; 2651c6a0718SPierre Ossman 2661c6a0718SPierre Ossman if (!data) 2671c6a0718SPierre Ossman return 0; 2681c6a0718SPierre Ossman 2691c6a0718SPierre Ossman DCSR(host->dma) = 0; 2701c6a0718SPierre Ossman dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, 2711c6a0718SPierre Ossman host->dma_dir); 2721c6a0718SPierre Ossman 2731c6a0718SPierre Ossman if (stat & STAT_READ_TIME_OUT) 27417b0429dSPierre Ossman data->error = -ETIMEDOUT; 2751c6a0718SPierre Ossman else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) 27617b0429dSPierre Ossman data->error = -EILSEQ; 2771c6a0718SPierre Ossman 2781c6a0718SPierre Ossman /* 2791c6a0718SPierre Ossman * There appears to be a hardware design bug here. There seems to 2801c6a0718SPierre Ossman * be no way to find out how much data was transferred to the card. 2811c6a0718SPierre Ossman * This means that if there was an error on any block, we mark all 2821c6a0718SPierre Ossman * data blocks as being in error. 2831c6a0718SPierre Ossman */ 28417b0429dSPierre Ossman if (!data->error) 2851c6a0718SPierre Ossman data->bytes_xfered = data->blocks * data->blksz; 2861c6a0718SPierre Ossman else 2871c6a0718SPierre Ossman data->bytes_xfered = 0; 2881c6a0718SPierre Ossman 2891c6a0718SPierre Ossman pxamci_disable_irq(host, DATA_TRAN_DONE); 2901c6a0718SPierre Ossman 2911c6a0718SPierre Ossman host->data = NULL; 2921c6a0718SPierre Ossman if (host->mrq->stop) { 2931c6a0718SPierre Ossman pxamci_stop_clock(host); 294df456f47SBridge Wu pxamci_start_cmd(host, host->mrq->stop, host->cmdat); 2951c6a0718SPierre Ossman } else { 2961c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq); 2971c6a0718SPierre Ossman } 2981c6a0718SPierre Ossman 2991c6a0718SPierre Ossman return 1; 3001c6a0718SPierre Ossman } 3011c6a0718SPierre Ossman 3021c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid) 3031c6a0718SPierre Ossman { 3041c6a0718SPierre Ossman struct pxamci_host *host = devid; 3051c6a0718SPierre Ossman unsigned int ireg; 3061c6a0718SPierre Ossman int handled = 0; 3071c6a0718SPierre Ossman 30881ab570fSBridge Wu ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); 3091c6a0718SPierre Ossman 3101c6a0718SPierre Ossman if (ireg) { 3111c6a0718SPierre Ossman unsigned stat = readl(host->base + MMC_STAT); 3121c6a0718SPierre Ossman 3131c6a0718SPierre Ossman pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); 3141c6a0718SPierre Ossman 3151c6a0718SPierre Ossman if (ireg & END_CMD_RES) 3161c6a0718SPierre Ossman handled |= pxamci_cmd_done(host, stat); 3171c6a0718SPierre Ossman if (ireg & DATA_TRAN_DONE) 3181c6a0718SPierre Ossman handled |= pxamci_data_done(host, stat); 3195d3ad4e8SBridge Wu if (ireg & SDIO_INT) { 3205d3ad4e8SBridge Wu mmc_signal_sdio_irq(host->mmc); 3215d3ad4e8SBridge Wu handled = 1; 3225d3ad4e8SBridge Wu } 3231c6a0718SPierre Ossman } 3241c6a0718SPierre Ossman 3251c6a0718SPierre Ossman return IRQ_RETVAL(handled); 3261c6a0718SPierre Ossman } 3271c6a0718SPierre Ossman 3281c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) 3291c6a0718SPierre Ossman { 3301c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 3311c6a0718SPierre Ossman unsigned int cmdat; 3321c6a0718SPierre Ossman 3331c6a0718SPierre Ossman WARN_ON(host->mrq != NULL); 3341c6a0718SPierre Ossman 3351c6a0718SPierre Ossman host->mrq = mrq; 3361c6a0718SPierre Ossman 3371c6a0718SPierre Ossman pxamci_stop_clock(host); 3381c6a0718SPierre Ossman 3391c6a0718SPierre Ossman cmdat = host->cmdat; 3401c6a0718SPierre Ossman host->cmdat &= ~CMDAT_INIT; 3411c6a0718SPierre Ossman 3421c6a0718SPierre Ossman if (mrq->data) { 3431c6a0718SPierre Ossman pxamci_setup_data(host, mrq->data); 3441c6a0718SPierre Ossman 3451c6a0718SPierre Ossman cmdat &= ~CMDAT_BUSY; 3461c6a0718SPierre Ossman cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; 3471c6a0718SPierre Ossman if (mrq->data->flags & MMC_DATA_WRITE) 3481c6a0718SPierre Ossman cmdat |= CMDAT_WRITE; 3491c6a0718SPierre Ossman 3501c6a0718SPierre Ossman if (mrq->data->flags & MMC_DATA_STREAM) 3511c6a0718SPierre Ossman cmdat |= CMDAT_STREAM; 3521c6a0718SPierre Ossman } 3531c6a0718SPierre Ossman 3541c6a0718SPierre Ossman pxamci_start_cmd(host, mrq->cmd, cmdat); 3551c6a0718SPierre Ossman } 3561c6a0718SPierre Ossman 3571c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc) 3581c6a0718SPierre Ossman { 3591c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 3601c6a0718SPierre Ossman 3611c6a0718SPierre Ossman if (host->pdata && host->pdata->get_ro) 3621c6a0718SPierre Ossman return host->pdata->get_ro(mmc_dev(mmc)); 3631c6a0718SPierre Ossman /* Host doesn't support read only detection so assume writeable */ 3641c6a0718SPierre Ossman return 0; 3651c6a0718SPierre Ossman } 3661c6a0718SPierre Ossman 3671c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 3681c6a0718SPierre Ossman { 3691c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 3701c6a0718SPierre Ossman 3711c6a0718SPierre Ossman if (ios->clock) { 372ebebd9b0SRussell King unsigned long rate = host->clkrate; 373ebebd9b0SRussell King unsigned int clk = rate / ios->clock; 374ebebd9b0SRussell King 375d8cb70d1SRussell King if (host->clkrt == CLKRT_OFF) 376d8cb70d1SRussell King clk_enable(host->clk); 377d8cb70d1SRussell King 378ebebd9b0SRussell King /* 379ebebd9b0SRussell King * clk might result in a lower divisor than we 380ebebd9b0SRussell King * desire. check for that condition and adjust 381ebebd9b0SRussell King * as appropriate. 382ebebd9b0SRussell King */ 383ebebd9b0SRussell King if (rate / clk > ios->clock) 3841c6a0718SPierre Ossman clk <<= 1; 3851c6a0718SPierre Ossman host->clkrt = fls(clk) - 1; 3861c6a0718SPierre Ossman 3871c6a0718SPierre Ossman /* 3881c6a0718SPierre Ossman * we write clkrt on the next command 3891c6a0718SPierre Ossman */ 3901c6a0718SPierre Ossman } else { 3911c6a0718SPierre Ossman pxamci_stop_clock(host); 392d8cb70d1SRussell King if (host->clkrt != CLKRT_OFF) { 393d8cb70d1SRussell King host->clkrt = CLKRT_OFF; 394ebebd9b0SRussell King clk_disable(host->clk); 3951c6a0718SPierre Ossman } 396d8cb70d1SRussell King } 3971c6a0718SPierre Ossman 3981c6a0718SPierre Ossman if (host->power_mode != ios->power_mode) { 3991c6a0718SPierre Ossman host->power_mode = ios->power_mode; 4001c6a0718SPierre Ossman 4011c6a0718SPierre Ossman if (host->pdata && host->pdata->setpower) 4021c6a0718SPierre Ossman host->pdata->setpower(mmc_dev(mmc), ios->vdd); 4031c6a0718SPierre Ossman 4041c6a0718SPierre Ossman if (ios->power_mode == MMC_POWER_ON) 4051c6a0718SPierre Ossman host->cmdat |= CMDAT_INIT; 4061c6a0718SPierre Ossman } 4071c6a0718SPierre Ossman 408df456f47SBridge Wu if (ios->bus_width == MMC_BUS_WIDTH_4) 409df456f47SBridge Wu host->cmdat |= CMDAT_SD_4DAT; 410df456f47SBridge Wu else 411df456f47SBridge Wu host->cmdat &= ~CMDAT_SD_4DAT; 412df456f47SBridge Wu 4131c6a0718SPierre Ossman pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", 4141c6a0718SPierre Ossman host->clkrt, host->cmdat); 4151c6a0718SPierre Ossman } 4161c6a0718SPierre Ossman 4175d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) 4185d3ad4e8SBridge Wu { 4195d3ad4e8SBridge Wu struct pxamci_host *pxa_host = mmc_priv(host); 4205d3ad4e8SBridge Wu 4215d3ad4e8SBridge Wu if (enable) 4225d3ad4e8SBridge Wu pxamci_enable_irq(pxa_host, SDIO_INT); 4235d3ad4e8SBridge Wu else 4245d3ad4e8SBridge Wu pxamci_disable_irq(pxa_host, SDIO_INT); 4255d3ad4e8SBridge Wu } 4265d3ad4e8SBridge Wu 4271c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = { 4281c6a0718SPierre Ossman .request = pxamci_request, 4291c6a0718SPierre Ossman .get_ro = pxamci_get_ro, 4301c6a0718SPierre Ossman .set_ios = pxamci_set_ios, 4315d3ad4e8SBridge Wu .enable_sdio_irq = pxamci_enable_sdio_irq, 4321c6a0718SPierre Ossman }; 4331c6a0718SPierre Ossman 4341c6a0718SPierre Ossman static void pxamci_dma_irq(int dma, void *devid) 4351c6a0718SPierre Ossman { 436c783837bSNicolas Pitre struct pxamci_host *host = devid; 437c783837bSNicolas Pitre int dcsr = DCSR(dma); 438c783837bSNicolas Pitre DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; 439c783837bSNicolas Pitre 440c783837bSNicolas Pitre if (dcsr & DCSR_ENDINTR) { 441c783837bSNicolas Pitre writel(BUF_PART_FULL, host->base + MMC_PRTBUF); 442c783837bSNicolas Pitre } else { 443c783837bSNicolas Pitre printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", 444c783837bSNicolas Pitre mmc_hostname(host->mmc), dma, dcsr); 445c783837bSNicolas Pitre host->data->error = -EIO; 446c783837bSNicolas Pitre pxamci_data_done(host, 0); 447c783837bSNicolas Pitre } 4481c6a0718SPierre Ossman } 4491c6a0718SPierre Ossman 4501c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid) 4511c6a0718SPierre Ossman { 4521c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(devid); 4531c6a0718SPierre Ossman 4541c6a0718SPierre Ossman mmc_detect_change(devid, host->pdata->detect_delay); 4551c6a0718SPierre Ossman return IRQ_HANDLED; 4561c6a0718SPierre Ossman } 4571c6a0718SPierre Ossman 4581c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev) 4591c6a0718SPierre Ossman { 4601c6a0718SPierre Ossman struct mmc_host *mmc; 4611c6a0718SPierre Ossman struct pxamci_host *host = NULL; 4621c6a0718SPierre Ossman struct resource *r; 4631c6a0718SPierre Ossman int ret, irq; 4641c6a0718SPierre Ossman 4651c6a0718SPierre Ossman r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4661c6a0718SPierre Ossman irq = platform_get_irq(pdev, 0); 4671c6a0718SPierre Ossman if (!r || irq < 0) 4681c6a0718SPierre Ossman return -ENXIO; 4691c6a0718SPierre Ossman 4701c6a0718SPierre Ossman r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); 4711c6a0718SPierre Ossman if (!r) 4721c6a0718SPierre Ossman return -EBUSY; 4731c6a0718SPierre Ossman 4741c6a0718SPierre Ossman mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev); 4751c6a0718SPierre Ossman if (!mmc) { 4761c6a0718SPierre Ossman ret = -ENOMEM; 4771c6a0718SPierre Ossman goto out; 4781c6a0718SPierre Ossman } 4791c6a0718SPierre Ossman 4801c6a0718SPierre Ossman mmc->ops = &pxamci_ops; 4811c6a0718SPierre Ossman 4821c6a0718SPierre Ossman /* 4831c6a0718SPierre Ossman * We can do SG-DMA, but we don't because we never know how much 4841c6a0718SPierre Ossman * data we successfully wrote to the card. 4851c6a0718SPierre Ossman */ 4861c6a0718SPierre Ossman mmc->max_phys_segs = NR_SG; 4871c6a0718SPierre Ossman 4881c6a0718SPierre Ossman /* 4891c6a0718SPierre Ossman * Our hardware DMA can handle a maximum of one page per SG entry. 4901c6a0718SPierre Ossman */ 4911c6a0718SPierre Ossman mmc->max_seg_size = PAGE_SIZE; 4921c6a0718SPierre Ossman 4931c6a0718SPierre Ossman /* 494fe2dc44eSNicolas Pitre * Block length register is only 10 bits before PXA27x. 4951c6a0718SPierre Ossman */ 496fe2dc44eSNicolas Pitre mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048; 4971c6a0718SPierre Ossman 4981c6a0718SPierre Ossman /* 4991c6a0718SPierre Ossman * Block count register is 16 bits. 5001c6a0718SPierre Ossman */ 5011c6a0718SPierre Ossman mmc->max_blk_count = 65535; 5021c6a0718SPierre Ossman 5031c6a0718SPierre Ossman host = mmc_priv(mmc); 5041c6a0718SPierre Ossman host->mmc = mmc; 5051c6a0718SPierre Ossman host->dma = -1; 5061c6a0718SPierre Ossman host->pdata = pdev->dev.platform_data; 507d8cb70d1SRussell King host->clkrt = CLKRT_OFF; 508ebebd9b0SRussell King 509ebebd9b0SRussell King host->clk = clk_get(&pdev->dev, "MMCCLK"); 510ebebd9b0SRussell King if (IS_ERR(host->clk)) { 511ebebd9b0SRussell King ret = PTR_ERR(host->clk); 512ebebd9b0SRussell King host->clk = NULL; 513ebebd9b0SRussell King goto out; 514ebebd9b0SRussell King } 515ebebd9b0SRussell King 516ebebd9b0SRussell King host->clkrate = clk_get_rate(host->clk); 517ebebd9b0SRussell King 518ebebd9b0SRussell King /* 519ebebd9b0SRussell King * Calculate minimum clock rate, rounding up. 520ebebd9b0SRussell King */ 521ebebd9b0SRussell King mmc->f_min = (host->clkrate + 63) / 64; 522ebebd9b0SRussell King mmc->f_max = host->clkrate; 523ebebd9b0SRussell King 5241c6a0718SPierre Ossman mmc->ocr_avail = host->pdata ? 5251c6a0718SPierre Ossman host->pdata->ocr_mask : 5261c6a0718SPierre Ossman MMC_VDD_32_33|MMC_VDD_33_34; 527df456f47SBridge Wu mmc->caps = 0; 5285d3ad4e8SBridge Wu host->cmdat = 0; 5295d3ad4e8SBridge Wu if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { 5305d3ad4e8SBridge Wu mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; 5315d3ad4e8SBridge Wu host->cmdat |= CMDAT_SDIO_INT_EN; 5325d3ad4e8SBridge Wu } 5331c6a0718SPierre Ossman 5341c6a0718SPierre Ossman host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); 5351c6a0718SPierre Ossman if (!host->sg_cpu) { 5361c6a0718SPierre Ossman ret = -ENOMEM; 5371c6a0718SPierre Ossman goto out; 5381c6a0718SPierre Ossman } 5391c6a0718SPierre Ossman 5401c6a0718SPierre Ossman spin_lock_init(&host->lock); 5411c6a0718SPierre Ossman host->res = r; 5421c6a0718SPierre Ossman host->irq = irq; 5431c6a0718SPierre Ossman host->imask = MMC_I_MASK_ALL; 5441c6a0718SPierre Ossman 5451c6a0718SPierre Ossman host->base = ioremap(r->start, SZ_4K); 5461c6a0718SPierre Ossman if (!host->base) { 5471c6a0718SPierre Ossman ret = -ENOMEM; 5481c6a0718SPierre Ossman goto out; 5491c6a0718SPierre Ossman } 5501c6a0718SPierre Ossman 5511c6a0718SPierre Ossman /* 5521c6a0718SPierre Ossman * Ensure that the host controller is shut down, and setup 5531c6a0718SPierre Ossman * with our defaults. 5541c6a0718SPierre Ossman */ 5551c6a0718SPierre Ossman pxamci_stop_clock(host); 5561c6a0718SPierre Ossman writel(0, host->base + MMC_SPI); 5571c6a0718SPierre Ossman writel(64, host->base + MMC_RESTO); 5581c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 5591c6a0718SPierre Ossman 5601c6a0718SPierre Ossman host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW, 5611c6a0718SPierre Ossman pxamci_dma_irq, host); 5621c6a0718SPierre Ossman if (host->dma < 0) { 5631c6a0718SPierre Ossman ret = -EBUSY; 5641c6a0718SPierre Ossman goto out; 5651c6a0718SPierre Ossman } 5661c6a0718SPierre Ossman 5671c6a0718SPierre Ossman ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); 5681c6a0718SPierre Ossman if (ret) 5691c6a0718SPierre Ossman goto out; 5701c6a0718SPierre Ossman 5711c6a0718SPierre Ossman platform_set_drvdata(pdev, mmc); 5721c6a0718SPierre Ossman 5731c6a0718SPierre Ossman if (host->pdata && host->pdata->init) 5741c6a0718SPierre Ossman host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); 5751c6a0718SPierre Ossman 5761c6a0718SPierre Ossman mmc_add_host(mmc); 5771c6a0718SPierre Ossman 5781c6a0718SPierre Ossman return 0; 5791c6a0718SPierre Ossman 5801c6a0718SPierre Ossman out: 5811c6a0718SPierre Ossman if (host) { 5821c6a0718SPierre Ossman if (host->dma >= 0) 5831c6a0718SPierre Ossman pxa_free_dma(host->dma); 5841c6a0718SPierre Ossman if (host->base) 5851c6a0718SPierre Ossman iounmap(host->base); 5861c6a0718SPierre Ossman if (host->sg_cpu) 5871c6a0718SPierre Ossman dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 588ebebd9b0SRussell King if (host->clk) 589ebebd9b0SRussell King clk_put(host->clk); 5901c6a0718SPierre Ossman } 5911c6a0718SPierre Ossman if (mmc) 5921c6a0718SPierre Ossman mmc_free_host(mmc); 5931c6a0718SPierre Ossman release_resource(r); 5941c6a0718SPierre Ossman return ret; 5951c6a0718SPierre Ossman } 5961c6a0718SPierre Ossman 5971c6a0718SPierre Ossman static int pxamci_remove(struct platform_device *pdev) 5981c6a0718SPierre Ossman { 5991c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(pdev); 6001c6a0718SPierre Ossman 6011c6a0718SPierre Ossman platform_set_drvdata(pdev, NULL); 6021c6a0718SPierre Ossman 6031c6a0718SPierre Ossman if (mmc) { 6041c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 6051c6a0718SPierre Ossman 6061c6a0718SPierre Ossman if (host->pdata && host->pdata->exit) 6071c6a0718SPierre Ossman host->pdata->exit(&pdev->dev, mmc); 6081c6a0718SPierre Ossman 6091c6a0718SPierre Ossman mmc_remove_host(mmc); 6101c6a0718SPierre Ossman 6111c6a0718SPierre Ossman pxamci_stop_clock(host); 6121c6a0718SPierre Ossman writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| 6131c6a0718SPierre Ossman END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, 6141c6a0718SPierre Ossman host->base + MMC_I_MASK); 6151c6a0718SPierre Ossman 6161c6a0718SPierre Ossman DRCMRRXMMC = 0; 6171c6a0718SPierre Ossman DRCMRTXMMC = 0; 6181c6a0718SPierre Ossman 6191c6a0718SPierre Ossman free_irq(host->irq, host); 6201c6a0718SPierre Ossman pxa_free_dma(host->dma); 6211c6a0718SPierre Ossman iounmap(host->base); 6221c6a0718SPierre Ossman dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 6231c6a0718SPierre Ossman 624ebebd9b0SRussell King clk_put(host->clk); 625ebebd9b0SRussell King 6261c6a0718SPierre Ossman release_resource(host->res); 6271c6a0718SPierre Ossman 6281c6a0718SPierre Ossman mmc_free_host(mmc); 6291c6a0718SPierre Ossman } 6301c6a0718SPierre Ossman return 0; 6311c6a0718SPierre Ossman } 6321c6a0718SPierre Ossman 6331c6a0718SPierre Ossman #ifdef CONFIG_PM 6341c6a0718SPierre Ossman static int pxamci_suspend(struct platform_device *dev, pm_message_t state) 6351c6a0718SPierre Ossman { 6361c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(dev); 6371c6a0718SPierre Ossman int ret = 0; 6381c6a0718SPierre Ossman 6391c6a0718SPierre Ossman if (mmc) 6401c6a0718SPierre Ossman ret = mmc_suspend_host(mmc, state); 6411c6a0718SPierre Ossman 6421c6a0718SPierre Ossman return ret; 6431c6a0718SPierre Ossman } 6441c6a0718SPierre Ossman 6451c6a0718SPierre Ossman static int pxamci_resume(struct platform_device *dev) 6461c6a0718SPierre Ossman { 6471c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(dev); 6481c6a0718SPierre Ossman int ret = 0; 6491c6a0718SPierre Ossman 6501c6a0718SPierre Ossman if (mmc) 6511c6a0718SPierre Ossman ret = mmc_resume_host(mmc); 6521c6a0718SPierre Ossman 6531c6a0718SPierre Ossman return ret; 6541c6a0718SPierre Ossman } 6551c6a0718SPierre Ossman #else 6561c6a0718SPierre Ossman #define pxamci_suspend NULL 6571c6a0718SPierre Ossman #define pxamci_resume NULL 6581c6a0718SPierre Ossman #endif 6591c6a0718SPierre Ossman 6601c6a0718SPierre Ossman static struct platform_driver pxamci_driver = { 6611c6a0718SPierre Ossman .probe = pxamci_probe, 6621c6a0718SPierre Ossman .remove = pxamci_remove, 6631c6a0718SPierre Ossman .suspend = pxamci_suspend, 6641c6a0718SPierre Ossman .resume = pxamci_resume, 6651c6a0718SPierre Ossman .driver = { 6661c6a0718SPierre Ossman .name = DRIVER_NAME, 6671c6a0718SPierre Ossman }, 6681c6a0718SPierre Ossman }; 6691c6a0718SPierre Ossman 6701c6a0718SPierre Ossman static int __init pxamci_init(void) 6711c6a0718SPierre Ossman { 6721c6a0718SPierre Ossman return platform_driver_register(&pxamci_driver); 6731c6a0718SPierre Ossman } 6741c6a0718SPierre Ossman 6751c6a0718SPierre Ossman static void __exit pxamci_exit(void) 6761c6a0718SPierre Ossman { 6771c6a0718SPierre Ossman platform_driver_unregister(&pxamci_driver); 6781c6a0718SPierre Ossman } 6791c6a0718SPierre Ossman 6801c6a0718SPierre Ossman module_init(pxamci_init); 6811c6a0718SPierre Ossman module_exit(pxamci_exit); 6821c6a0718SPierre Ossman 6831c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); 6841c6a0718SPierre Ossman MODULE_LICENSE("GPL"); 685