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> 2905678a96SRussell King #include <linux/io.h> 301c6a0718SPierre Ossman 311c6a0718SPierre Ossman #include <asm/sizes.h> 321c6a0718SPierre Ossman 33dcea83adSRussell King #include <mach/dma.h> 3405678a96SRussell King #include <mach/hardware.h> 35a09e64fbSRussell King #include <mach/pxa-regs.h> 36a09e64fbSRussell King #include <mach/mmc.h> 371c6a0718SPierre Ossman 381c6a0718SPierre Ossman #include "pxamci.h" 391c6a0718SPierre Ossman 401c6a0718SPierre Ossman #define DRIVER_NAME "pxa2xx-mci" 411c6a0718SPierre Ossman 421c6a0718SPierre Ossman #define NR_SG 1 43d8cb70d1SRussell King #define CLKRT_OFF (~0) 441c6a0718SPierre Ossman 451c6a0718SPierre Ossman struct pxamci_host { 461c6a0718SPierre Ossman struct mmc_host *mmc; 471c6a0718SPierre Ossman spinlock_t lock; 481c6a0718SPierre Ossman struct resource *res; 491c6a0718SPierre Ossman void __iomem *base; 50ebebd9b0SRussell King struct clk *clk; 51ebebd9b0SRussell King unsigned long clkrate; 521c6a0718SPierre Ossman int irq; 531c6a0718SPierre Ossman int dma; 541c6a0718SPierre Ossman unsigned int clkrt; 551c6a0718SPierre Ossman unsigned int cmdat; 561c6a0718SPierre Ossman unsigned int imask; 571c6a0718SPierre Ossman unsigned int power_mode; 581c6a0718SPierre Ossman struct pxamci_platform_data *pdata; 591c6a0718SPierre Ossman 601c6a0718SPierre Ossman struct mmc_request *mrq; 611c6a0718SPierre Ossman struct mmc_command *cmd; 621c6a0718SPierre Ossman struct mmc_data *data; 631c6a0718SPierre Ossman 641c6a0718SPierre Ossman dma_addr_t sg_dma; 651c6a0718SPierre Ossman struct pxa_dma_desc *sg_cpu; 661c6a0718SPierre Ossman unsigned int dma_len; 671c6a0718SPierre Ossman 681c6a0718SPierre Ossman unsigned int dma_dir; 699a788c6bSBridge Wu unsigned int dma_drcmrrx; 709a788c6bSBridge Wu unsigned int dma_drcmrtx; 711c6a0718SPierre Ossman }; 721c6a0718SPierre Ossman 731c6a0718SPierre Ossman static void pxamci_stop_clock(struct pxamci_host *host) 741c6a0718SPierre Ossman { 751c6a0718SPierre Ossman if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { 761c6a0718SPierre Ossman unsigned long timeout = 10000; 771c6a0718SPierre Ossman unsigned int v; 781c6a0718SPierre Ossman 791c6a0718SPierre Ossman writel(STOP_CLOCK, host->base + MMC_STRPCL); 801c6a0718SPierre Ossman 811c6a0718SPierre Ossman do { 821c6a0718SPierre Ossman v = readl(host->base + MMC_STAT); 831c6a0718SPierre Ossman if (!(v & STAT_CLK_EN)) 841c6a0718SPierre Ossman break; 851c6a0718SPierre Ossman udelay(1); 861c6a0718SPierre Ossman } while (timeout--); 871c6a0718SPierre Ossman 881c6a0718SPierre Ossman if (v & STAT_CLK_EN) 891c6a0718SPierre Ossman dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); 901c6a0718SPierre Ossman } 911c6a0718SPierre Ossman } 921c6a0718SPierre Ossman 931c6a0718SPierre Ossman static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) 941c6a0718SPierre Ossman { 951c6a0718SPierre Ossman unsigned long flags; 961c6a0718SPierre Ossman 971c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags); 981c6a0718SPierre Ossman host->imask &= ~mask; 991c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 1001c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1011c6a0718SPierre Ossman } 1021c6a0718SPierre Ossman 1031c6a0718SPierre Ossman static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) 1041c6a0718SPierre Ossman { 1051c6a0718SPierre Ossman unsigned long flags; 1061c6a0718SPierre Ossman 1071c6a0718SPierre Ossman spin_lock_irqsave(&host->lock, flags); 1081c6a0718SPierre Ossman host->imask |= mask; 1091c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 1101c6a0718SPierre Ossman spin_unlock_irqrestore(&host->lock, flags); 1111c6a0718SPierre Ossman } 1121c6a0718SPierre Ossman 1131c6a0718SPierre Ossman static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) 1141c6a0718SPierre Ossman { 1151c6a0718SPierre Ossman unsigned int nob = data->blocks; 1161c6a0718SPierre Ossman unsigned long long clks; 1171c6a0718SPierre Ossman unsigned int timeout; 11897f8571eSPhilipp Zabel bool dalgn = 0; 1191c6a0718SPierre Ossman u32 dcmd; 1201c6a0718SPierre Ossman int i; 1211c6a0718SPierre Ossman 1221c6a0718SPierre Ossman host->data = data; 1231c6a0718SPierre Ossman 1241c6a0718SPierre Ossman if (data->flags & MMC_DATA_STREAM) 1251c6a0718SPierre Ossman nob = 0xffff; 1261c6a0718SPierre Ossman 1271c6a0718SPierre Ossman writel(nob, host->base + MMC_NOB); 1281c6a0718SPierre Ossman writel(data->blksz, host->base + MMC_BLKLEN); 1291c6a0718SPierre Ossman 130ebebd9b0SRussell King clks = (unsigned long long)data->timeout_ns * host->clkrate; 1311c6a0718SPierre Ossman do_div(clks, 1000000000UL); 1321c6a0718SPierre Ossman timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); 1331c6a0718SPierre Ossman writel((timeout + 255) / 256, host->base + MMC_RDTO); 1341c6a0718SPierre Ossman 1351c6a0718SPierre Ossman if (data->flags & MMC_DATA_READ) { 1361c6a0718SPierre Ossman host->dma_dir = DMA_FROM_DEVICE; 1371c6a0718SPierre Ossman dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; 1389a788c6bSBridge Wu DRCMR(host->dma_drcmrtx) = 0; 1399a788c6bSBridge Wu DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD; 1401c6a0718SPierre Ossman } else { 1411c6a0718SPierre Ossman host->dma_dir = DMA_TO_DEVICE; 1421c6a0718SPierre Ossman dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; 1439a788c6bSBridge Wu DRCMR(host->dma_drcmrrx) = 0; 1449a788c6bSBridge Wu DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD; 1451c6a0718SPierre Ossman } 1461c6a0718SPierre Ossman 1471c6a0718SPierre Ossman dcmd |= DCMD_BURST32 | DCMD_WIDTH1; 1481c6a0718SPierre Ossman 1491c6a0718SPierre Ossman host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 1501c6a0718SPierre Ossman host->dma_dir); 1511c6a0718SPierre Ossman 1521c6a0718SPierre Ossman for (i = 0; i < host->dma_len; i++) { 153c783837bSNicolas Pitre unsigned int length = sg_dma_len(&data->sg[i]); 154c783837bSNicolas Pitre host->sg_cpu[i].dcmd = dcmd | length; 155c783837bSNicolas Pitre if (length & 31 && !(data->flags & MMC_DATA_READ)) 156c783837bSNicolas Pitre host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; 15797f8571eSPhilipp Zabel /* Not aligned to 8-byte boundary? */ 15897f8571eSPhilipp Zabel if (sg_dma_address(&data->sg[i]) & 0x7) 15997f8571eSPhilipp Zabel dalgn = 1; 1601c6a0718SPierre Ossman if (data->flags & MMC_DATA_READ) { 1611c6a0718SPierre Ossman host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; 1621c6a0718SPierre Ossman host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); 1631c6a0718SPierre Ossman } else { 1641c6a0718SPierre Ossman host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); 1651c6a0718SPierre Ossman host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; 1661c6a0718SPierre Ossman } 1671c6a0718SPierre Ossman host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * 1681c6a0718SPierre Ossman sizeof(struct pxa_dma_desc); 1691c6a0718SPierre Ossman } 1701c6a0718SPierre Ossman host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; 1711c6a0718SPierre Ossman wmb(); 1721c6a0718SPierre Ossman 17397f8571eSPhilipp Zabel /* 17497f8571eSPhilipp Zabel * The PXA27x DMA controller encounters overhead when working with 17597f8571eSPhilipp Zabel * unaligned (to 8-byte boundaries) data, so switch on byte alignment 17697f8571eSPhilipp Zabel * mode only if we have unaligned data. 17797f8571eSPhilipp Zabel */ 17897f8571eSPhilipp Zabel if (dalgn) 17997f8571eSPhilipp Zabel DALGN |= (1 << host->dma); 18097f8571eSPhilipp Zabel else 1814fe16897SKarl Beldan DALGN &= ~(1 << host->dma); 1821c6a0718SPierre Ossman DDADR(host->dma) = host->sg_dma; 183b6018958SCliff Brake 184b6018958SCliff Brake /* 185b6018958SCliff Brake * workaround for erratum #91: 186b6018958SCliff Brake * only start DMA now if we are doing a read, 187b6018958SCliff Brake * otherwise we wait until CMD/RESP has finished 188b6018958SCliff Brake * before starting DMA. 189b6018958SCliff Brake */ 190b6018958SCliff Brake if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) 1911c6a0718SPierre Ossman DCSR(host->dma) = DCSR_RUN; 1921c6a0718SPierre Ossman } 1931c6a0718SPierre Ossman 1941c6a0718SPierre Ossman static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) 1951c6a0718SPierre Ossman { 1961c6a0718SPierre Ossman WARN_ON(host->cmd != NULL); 1971c6a0718SPierre Ossman host->cmd = cmd; 1981c6a0718SPierre Ossman 1991c6a0718SPierre Ossman if (cmd->flags & MMC_RSP_BUSY) 2001c6a0718SPierre Ossman cmdat |= CMDAT_BUSY; 2011c6a0718SPierre Ossman 2021c6a0718SPierre Ossman #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) 2031c6a0718SPierre Ossman switch (RSP_TYPE(mmc_resp_type(cmd))) { 2041c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ 2051c6a0718SPierre Ossman cmdat |= CMDAT_RESP_SHORT; 2061c6a0718SPierre Ossman break; 2071c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R3): 2081c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R3; 2091c6a0718SPierre Ossman break; 2101c6a0718SPierre Ossman case RSP_TYPE(MMC_RSP_R2): 2111c6a0718SPierre Ossman cmdat |= CMDAT_RESP_R2; 2121c6a0718SPierre Ossman break; 2131c6a0718SPierre Ossman default: 2141c6a0718SPierre Ossman break; 2151c6a0718SPierre Ossman } 2161c6a0718SPierre Ossman 2171c6a0718SPierre Ossman writel(cmd->opcode, host->base + MMC_CMD); 2181c6a0718SPierre Ossman writel(cmd->arg >> 16, host->base + MMC_ARGH); 2191c6a0718SPierre Ossman writel(cmd->arg & 0xffff, host->base + MMC_ARGL); 2201c6a0718SPierre Ossman writel(cmdat, host->base + MMC_CMDAT); 2211c6a0718SPierre Ossman writel(host->clkrt, host->base + MMC_CLKRT); 2221c6a0718SPierre Ossman 2231c6a0718SPierre Ossman writel(START_CLOCK, host->base + MMC_STRPCL); 2241c6a0718SPierre Ossman 2251c6a0718SPierre Ossman pxamci_enable_irq(host, END_CMD_RES); 2261c6a0718SPierre Ossman } 2271c6a0718SPierre Ossman 2281c6a0718SPierre Ossman static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) 2291c6a0718SPierre Ossman { 2301c6a0718SPierre Ossman host->mrq = NULL; 2311c6a0718SPierre Ossman host->cmd = NULL; 2321c6a0718SPierre Ossman host->data = NULL; 2331c6a0718SPierre Ossman mmc_request_done(host->mmc, mrq); 2341c6a0718SPierre Ossman } 2351c6a0718SPierre Ossman 2361c6a0718SPierre Ossman static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) 2371c6a0718SPierre Ossman { 2381c6a0718SPierre Ossman struct mmc_command *cmd = host->cmd; 2391c6a0718SPierre Ossman int i; 2401c6a0718SPierre Ossman u32 v; 2411c6a0718SPierre Ossman 2421c6a0718SPierre Ossman if (!cmd) 2431c6a0718SPierre Ossman return 0; 2441c6a0718SPierre Ossman 2451c6a0718SPierre Ossman host->cmd = NULL; 2461c6a0718SPierre Ossman 2471c6a0718SPierre Ossman /* 2481c6a0718SPierre Ossman * Did I mention this is Sick. We always need to 2491c6a0718SPierre Ossman * discard the upper 8 bits of the first 16-bit word. 2501c6a0718SPierre Ossman */ 2511c6a0718SPierre Ossman v = readl(host->base + MMC_RES) & 0xffff; 2521c6a0718SPierre Ossman for (i = 0; i < 4; i++) { 2531c6a0718SPierre Ossman u32 w1 = readl(host->base + MMC_RES) & 0xffff; 2541c6a0718SPierre Ossman u32 w2 = readl(host->base + MMC_RES) & 0xffff; 2551c6a0718SPierre Ossman cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; 2561c6a0718SPierre Ossman v = w2; 2571c6a0718SPierre Ossman } 2581c6a0718SPierre Ossman 2591c6a0718SPierre Ossman if (stat & STAT_TIME_OUT_RESPONSE) { 26017b0429dSPierre Ossman cmd->error = -ETIMEDOUT; 2611c6a0718SPierre Ossman } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { 2621c6a0718SPierre Ossman /* 2631c6a0718SPierre Ossman * workaround for erratum #42: 2641c6a0718SPierre Ossman * Intel PXA27x Family Processor Specification Update Rev 001 26590e07d9fSNicolas Pitre * A bogus CRC error can appear if the msb of a 136 bit 26690e07d9fSNicolas Pitre * response is a one. 2671c6a0718SPierre Ossman */ 268e10a854cSCliff Brake if (cpu_is_pxa27x() && 269e10a854cSCliff Brake (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000)) 2701c6a0718SPierre Ossman pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); 271e10a854cSCliff Brake else 27217b0429dSPierre Ossman cmd->error = -EILSEQ; 2731c6a0718SPierre Ossman } 2741c6a0718SPierre Ossman 2751c6a0718SPierre Ossman pxamci_disable_irq(host, END_CMD_RES); 27617b0429dSPierre Ossman if (host->data && !cmd->error) { 2771c6a0718SPierre Ossman pxamci_enable_irq(host, DATA_TRAN_DONE); 278b6018958SCliff Brake /* 279b6018958SCliff Brake * workaround for erratum #91, if doing write 280b6018958SCliff Brake * enable DMA late 281b6018958SCliff Brake */ 282b6018958SCliff Brake if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) 283b6018958SCliff Brake DCSR(host->dma) = DCSR_RUN; 2841c6a0718SPierre Ossman } else { 2851c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq); 2861c6a0718SPierre Ossman } 2871c6a0718SPierre Ossman 2881c6a0718SPierre Ossman return 1; 2891c6a0718SPierre Ossman } 2901c6a0718SPierre Ossman 2911c6a0718SPierre Ossman static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) 2921c6a0718SPierre Ossman { 2931c6a0718SPierre Ossman struct mmc_data *data = host->data; 2941c6a0718SPierre Ossman 2951c6a0718SPierre Ossman if (!data) 2961c6a0718SPierre Ossman return 0; 2971c6a0718SPierre Ossman 2981c6a0718SPierre Ossman DCSR(host->dma) = 0; 299c00a46abSVernon Sauder dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 3001c6a0718SPierre Ossman host->dma_dir); 3011c6a0718SPierre Ossman 3021c6a0718SPierre Ossman if (stat & STAT_READ_TIME_OUT) 30317b0429dSPierre Ossman data->error = -ETIMEDOUT; 3041c6a0718SPierre Ossman else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) 30517b0429dSPierre Ossman data->error = -EILSEQ; 3061c6a0718SPierre Ossman 3071c6a0718SPierre Ossman /* 3081c6a0718SPierre Ossman * There appears to be a hardware design bug here. There seems to 3091c6a0718SPierre Ossman * be no way to find out how much data was transferred to the card. 3101c6a0718SPierre Ossman * This means that if there was an error on any block, we mark all 3111c6a0718SPierre Ossman * data blocks as being in error. 3121c6a0718SPierre Ossman */ 31317b0429dSPierre Ossman if (!data->error) 3141c6a0718SPierre Ossman data->bytes_xfered = data->blocks * data->blksz; 3151c6a0718SPierre Ossman else 3161c6a0718SPierre Ossman data->bytes_xfered = 0; 3171c6a0718SPierre Ossman 3181c6a0718SPierre Ossman pxamci_disable_irq(host, DATA_TRAN_DONE); 3191c6a0718SPierre Ossman 3201c6a0718SPierre Ossman host->data = NULL; 3211c6a0718SPierre Ossman if (host->mrq->stop) { 3221c6a0718SPierre Ossman pxamci_stop_clock(host); 323df456f47SBridge Wu pxamci_start_cmd(host, host->mrq->stop, host->cmdat); 3241c6a0718SPierre Ossman } else { 3251c6a0718SPierre Ossman pxamci_finish_request(host, host->mrq); 3261c6a0718SPierre Ossman } 3271c6a0718SPierre Ossman 3281c6a0718SPierre Ossman return 1; 3291c6a0718SPierre Ossman } 3301c6a0718SPierre Ossman 3311c6a0718SPierre Ossman static irqreturn_t pxamci_irq(int irq, void *devid) 3321c6a0718SPierre Ossman { 3331c6a0718SPierre Ossman struct pxamci_host *host = devid; 3341c6a0718SPierre Ossman unsigned int ireg; 3351c6a0718SPierre Ossman int handled = 0; 3361c6a0718SPierre Ossman 33781ab570fSBridge Wu ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); 3381c6a0718SPierre Ossman 3391c6a0718SPierre Ossman if (ireg) { 3401c6a0718SPierre Ossman unsigned stat = readl(host->base + MMC_STAT); 3411c6a0718SPierre Ossman 3421c6a0718SPierre Ossman pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); 3431c6a0718SPierre Ossman 3441c6a0718SPierre Ossman if (ireg & END_CMD_RES) 3451c6a0718SPierre Ossman handled |= pxamci_cmd_done(host, stat); 3461c6a0718SPierre Ossman if (ireg & DATA_TRAN_DONE) 3471c6a0718SPierre Ossman handled |= pxamci_data_done(host, stat); 3485d3ad4e8SBridge Wu if (ireg & SDIO_INT) { 3495d3ad4e8SBridge Wu mmc_signal_sdio_irq(host->mmc); 3505d3ad4e8SBridge Wu handled = 1; 3515d3ad4e8SBridge Wu } 3521c6a0718SPierre Ossman } 3531c6a0718SPierre Ossman 3541c6a0718SPierre Ossman return IRQ_RETVAL(handled); 3551c6a0718SPierre Ossman } 3561c6a0718SPierre Ossman 3571c6a0718SPierre Ossman static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) 3581c6a0718SPierre Ossman { 3591c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 3601c6a0718SPierre Ossman unsigned int cmdat; 3611c6a0718SPierre Ossman 3621c6a0718SPierre Ossman WARN_ON(host->mrq != NULL); 3631c6a0718SPierre Ossman 3641c6a0718SPierre Ossman host->mrq = mrq; 3651c6a0718SPierre Ossman 3661c6a0718SPierre Ossman pxamci_stop_clock(host); 3671c6a0718SPierre Ossman 3681c6a0718SPierre Ossman cmdat = host->cmdat; 3691c6a0718SPierre Ossman host->cmdat &= ~CMDAT_INIT; 3701c6a0718SPierre Ossman 3711c6a0718SPierre Ossman if (mrq->data) { 3721c6a0718SPierre Ossman pxamci_setup_data(host, mrq->data); 3731c6a0718SPierre Ossman 3741c6a0718SPierre Ossman cmdat &= ~CMDAT_BUSY; 3751c6a0718SPierre Ossman cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; 3761c6a0718SPierre Ossman if (mrq->data->flags & MMC_DATA_WRITE) 3771c6a0718SPierre Ossman cmdat |= CMDAT_WRITE; 3781c6a0718SPierre Ossman 3791c6a0718SPierre Ossman if (mrq->data->flags & MMC_DATA_STREAM) 3801c6a0718SPierre Ossman cmdat |= CMDAT_STREAM; 3811c6a0718SPierre Ossman } 3821c6a0718SPierre Ossman 3831c6a0718SPierre Ossman pxamci_start_cmd(host, mrq->cmd, cmdat); 3841c6a0718SPierre Ossman } 3851c6a0718SPierre Ossman 3861c6a0718SPierre Ossman static int pxamci_get_ro(struct mmc_host *mmc) 3871c6a0718SPierre Ossman { 3881c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 3891c6a0718SPierre Ossman 3901c6a0718SPierre Ossman if (host->pdata && host->pdata->get_ro) 39108f80bb5SAnton Vorontsov return !!host->pdata->get_ro(mmc_dev(mmc)); 39208f80bb5SAnton Vorontsov /* 39308f80bb5SAnton Vorontsov * Board doesn't support read only detection; let the mmc core 39408f80bb5SAnton Vorontsov * decide what to do. 39508f80bb5SAnton Vorontsov */ 39608f80bb5SAnton Vorontsov return -ENOSYS; 3971c6a0718SPierre Ossman } 3981c6a0718SPierre Ossman 3991c6a0718SPierre Ossman static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 4001c6a0718SPierre Ossman { 4011c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 4021c6a0718SPierre Ossman 4031c6a0718SPierre Ossman if (ios->clock) { 404ebebd9b0SRussell King unsigned long rate = host->clkrate; 405ebebd9b0SRussell King unsigned int clk = rate / ios->clock; 406ebebd9b0SRussell King 407d8cb70d1SRussell King if (host->clkrt == CLKRT_OFF) 408d8cb70d1SRussell King clk_enable(host->clk); 409d8cb70d1SRussell King 41064eb036aSBridge Wu if (ios->clock == 26000000) { 41164eb036aSBridge Wu /* to support 26MHz on pxa300/pxa310 */ 41264eb036aSBridge Wu host->clkrt = 7; 41364eb036aSBridge Wu } else { 41464eb036aSBridge Wu /* to handle (19.5MHz, 26MHz) */ 41564eb036aSBridge Wu if (!clk) 41664eb036aSBridge Wu clk = 1; 41764eb036aSBridge Wu 418ebebd9b0SRussell King /* 419ebebd9b0SRussell King * clk might result in a lower divisor than we 420ebebd9b0SRussell King * desire. check for that condition and adjust 421ebebd9b0SRussell King * as appropriate. 422ebebd9b0SRussell King */ 423ebebd9b0SRussell King if (rate / clk > ios->clock) 4241c6a0718SPierre Ossman clk <<= 1; 4251c6a0718SPierre Ossman host->clkrt = fls(clk) - 1; 42664eb036aSBridge Wu } 4271c6a0718SPierre Ossman 4281c6a0718SPierre Ossman /* 4291c6a0718SPierre Ossman * we write clkrt on the next command 4301c6a0718SPierre Ossman */ 4311c6a0718SPierre Ossman } else { 4321c6a0718SPierre Ossman pxamci_stop_clock(host); 433d8cb70d1SRussell King if (host->clkrt != CLKRT_OFF) { 434d8cb70d1SRussell King host->clkrt = CLKRT_OFF; 435ebebd9b0SRussell King clk_disable(host->clk); 4361c6a0718SPierre Ossman } 437d8cb70d1SRussell King } 4381c6a0718SPierre Ossman 4391c6a0718SPierre Ossman if (host->power_mode != ios->power_mode) { 4401c6a0718SPierre Ossman host->power_mode = ios->power_mode; 4411c6a0718SPierre Ossman 4421c6a0718SPierre Ossman if (host->pdata && host->pdata->setpower) 4431c6a0718SPierre Ossman host->pdata->setpower(mmc_dev(mmc), ios->vdd); 4441c6a0718SPierre Ossman 4451c6a0718SPierre Ossman if (ios->power_mode == MMC_POWER_ON) 4461c6a0718SPierre Ossman host->cmdat |= CMDAT_INIT; 4471c6a0718SPierre Ossman } 4481c6a0718SPierre Ossman 449df456f47SBridge Wu if (ios->bus_width == MMC_BUS_WIDTH_4) 450df456f47SBridge Wu host->cmdat |= CMDAT_SD_4DAT; 451df456f47SBridge Wu else 452df456f47SBridge Wu host->cmdat &= ~CMDAT_SD_4DAT; 453df456f47SBridge Wu 4541c6a0718SPierre Ossman pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", 4551c6a0718SPierre Ossman host->clkrt, host->cmdat); 4561c6a0718SPierre Ossman } 4571c6a0718SPierre Ossman 4585d3ad4e8SBridge Wu static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) 4595d3ad4e8SBridge Wu { 4605d3ad4e8SBridge Wu struct pxamci_host *pxa_host = mmc_priv(host); 4615d3ad4e8SBridge Wu 4625d3ad4e8SBridge Wu if (enable) 4635d3ad4e8SBridge Wu pxamci_enable_irq(pxa_host, SDIO_INT); 4645d3ad4e8SBridge Wu else 4655d3ad4e8SBridge Wu pxamci_disable_irq(pxa_host, SDIO_INT); 4665d3ad4e8SBridge Wu } 4675d3ad4e8SBridge Wu 4681c6a0718SPierre Ossman static const struct mmc_host_ops pxamci_ops = { 4691c6a0718SPierre Ossman .request = pxamci_request, 4701c6a0718SPierre Ossman .get_ro = pxamci_get_ro, 4711c6a0718SPierre Ossman .set_ios = pxamci_set_ios, 4725d3ad4e8SBridge Wu .enable_sdio_irq = pxamci_enable_sdio_irq, 4731c6a0718SPierre Ossman }; 4741c6a0718SPierre Ossman 4751c6a0718SPierre Ossman static void pxamci_dma_irq(int dma, void *devid) 4761c6a0718SPierre Ossman { 477c783837bSNicolas Pitre struct pxamci_host *host = devid; 478c783837bSNicolas Pitre int dcsr = DCSR(dma); 479c783837bSNicolas Pitre DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; 480c783837bSNicolas Pitre 481c783837bSNicolas Pitre if (dcsr & DCSR_ENDINTR) { 482c783837bSNicolas Pitre writel(BUF_PART_FULL, host->base + MMC_PRTBUF); 483c783837bSNicolas Pitre } else { 484c783837bSNicolas Pitre printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", 485c783837bSNicolas Pitre mmc_hostname(host->mmc), dma, dcsr); 486c783837bSNicolas Pitre host->data->error = -EIO; 487c783837bSNicolas Pitre pxamci_data_done(host, 0); 488c783837bSNicolas Pitre } 4891c6a0718SPierre Ossman } 4901c6a0718SPierre Ossman 4911c6a0718SPierre Ossman static irqreturn_t pxamci_detect_irq(int irq, void *devid) 4921c6a0718SPierre Ossman { 4931c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(devid); 4941c6a0718SPierre Ossman 4951c6a0718SPierre Ossman mmc_detect_change(devid, host->pdata->detect_delay); 4961c6a0718SPierre Ossman return IRQ_HANDLED; 4971c6a0718SPierre Ossman } 4981c6a0718SPierre Ossman 4991c6a0718SPierre Ossman static int pxamci_probe(struct platform_device *pdev) 5001c6a0718SPierre Ossman { 5011c6a0718SPierre Ossman struct mmc_host *mmc; 5021c6a0718SPierre Ossman struct pxamci_host *host = NULL; 5039a788c6bSBridge Wu struct resource *r, *dmarx, *dmatx; 5041c6a0718SPierre Ossman int ret, irq; 5051c6a0718SPierre Ossman 5061c6a0718SPierre Ossman r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5071c6a0718SPierre Ossman irq = platform_get_irq(pdev, 0); 5081c6a0718SPierre Ossman if (!r || irq < 0) 5091c6a0718SPierre Ossman return -ENXIO; 5101c6a0718SPierre Ossman 5111c6a0718SPierre Ossman r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); 5121c6a0718SPierre Ossman if (!r) 5131c6a0718SPierre Ossman return -EBUSY; 5141c6a0718SPierre Ossman 5151c6a0718SPierre Ossman mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev); 5161c6a0718SPierre Ossman if (!mmc) { 5171c6a0718SPierre Ossman ret = -ENOMEM; 5181c6a0718SPierre Ossman goto out; 5191c6a0718SPierre Ossman } 5201c6a0718SPierre Ossman 5211c6a0718SPierre Ossman mmc->ops = &pxamci_ops; 5221c6a0718SPierre Ossman 5231c6a0718SPierre Ossman /* 5241c6a0718SPierre Ossman * We can do SG-DMA, but we don't because we never know how much 5251c6a0718SPierre Ossman * data we successfully wrote to the card. 5261c6a0718SPierre Ossman */ 5271c6a0718SPierre Ossman mmc->max_phys_segs = NR_SG; 5281c6a0718SPierre Ossman 5291c6a0718SPierre Ossman /* 5301c6a0718SPierre Ossman * Our hardware DMA can handle a maximum of one page per SG entry. 5311c6a0718SPierre Ossman */ 5321c6a0718SPierre Ossman mmc->max_seg_size = PAGE_SIZE; 5331c6a0718SPierre Ossman 5341c6a0718SPierre Ossman /* 535fe2dc44eSNicolas Pitre * Block length register is only 10 bits before PXA27x. 5361c6a0718SPierre Ossman */ 5370ffcbfd5SEric Miao mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048; 5381c6a0718SPierre Ossman 5391c6a0718SPierre Ossman /* 5401c6a0718SPierre Ossman * Block count register is 16 bits. 5411c6a0718SPierre Ossman */ 5421c6a0718SPierre Ossman mmc->max_blk_count = 65535; 5431c6a0718SPierre Ossman 5441c6a0718SPierre Ossman host = mmc_priv(mmc); 5451c6a0718SPierre Ossman host->mmc = mmc; 5461c6a0718SPierre Ossman host->dma = -1; 5471c6a0718SPierre Ossman host->pdata = pdev->dev.platform_data; 548d8cb70d1SRussell King host->clkrt = CLKRT_OFF; 549ebebd9b0SRussell King 550e0d8b13aSRussell King host->clk = clk_get(&pdev->dev, NULL); 551ebebd9b0SRussell King if (IS_ERR(host->clk)) { 552ebebd9b0SRussell King ret = PTR_ERR(host->clk); 553ebebd9b0SRussell King host->clk = NULL; 554ebebd9b0SRussell King goto out; 555ebebd9b0SRussell King } 556ebebd9b0SRussell King 557ebebd9b0SRussell King host->clkrate = clk_get_rate(host->clk); 558ebebd9b0SRussell King 559ebebd9b0SRussell King /* 560ebebd9b0SRussell King * Calculate minimum clock rate, rounding up. 561ebebd9b0SRussell King */ 562ebebd9b0SRussell King mmc->f_min = (host->clkrate + 63) / 64; 56364eb036aSBridge Wu mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000 56464eb036aSBridge Wu : host->clkrate; 565ebebd9b0SRussell King 5661c6a0718SPierre Ossman mmc->ocr_avail = host->pdata ? 5671c6a0718SPierre Ossman host->pdata->ocr_mask : 5681c6a0718SPierre Ossman MMC_VDD_32_33|MMC_VDD_33_34; 569df456f47SBridge Wu mmc->caps = 0; 5705d3ad4e8SBridge Wu host->cmdat = 0; 5710ffcbfd5SEric Miao if (!cpu_is_pxa25x()) { 5725d3ad4e8SBridge Wu mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; 5735d3ad4e8SBridge Wu host->cmdat |= CMDAT_SDIO_INT_EN; 57464eb036aSBridge Wu if (cpu_is_pxa300() || cpu_is_pxa310()) 57564eb036aSBridge Wu mmc->caps |= MMC_CAP_MMC_HIGHSPEED | 57664eb036aSBridge Wu MMC_CAP_SD_HIGHSPEED; 5775d3ad4e8SBridge Wu } 5781c6a0718SPierre Ossman 5791c6a0718SPierre Ossman host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); 5801c6a0718SPierre Ossman if (!host->sg_cpu) { 5811c6a0718SPierre Ossman ret = -ENOMEM; 5821c6a0718SPierre Ossman goto out; 5831c6a0718SPierre Ossman } 5841c6a0718SPierre Ossman 5851c6a0718SPierre Ossman spin_lock_init(&host->lock); 5861c6a0718SPierre Ossman host->res = r; 5871c6a0718SPierre Ossman host->irq = irq; 5881c6a0718SPierre Ossman host->imask = MMC_I_MASK_ALL; 5891c6a0718SPierre Ossman 5901c6a0718SPierre Ossman host->base = ioremap(r->start, SZ_4K); 5911c6a0718SPierre Ossman if (!host->base) { 5921c6a0718SPierre Ossman ret = -ENOMEM; 5931c6a0718SPierre Ossman goto out; 5941c6a0718SPierre Ossman } 5951c6a0718SPierre Ossman 5961c6a0718SPierre Ossman /* 5971c6a0718SPierre Ossman * Ensure that the host controller is shut down, and setup 5981c6a0718SPierre Ossman * with our defaults. 5991c6a0718SPierre Ossman */ 6001c6a0718SPierre Ossman pxamci_stop_clock(host); 6011c6a0718SPierre Ossman writel(0, host->base + MMC_SPI); 6021c6a0718SPierre Ossman writel(64, host->base + MMC_RESTO); 6031c6a0718SPierre Ossman writel(host->imask, host->base + MMC_I_MASK); 6041c6a0718SPierre Ossman 6051c6a0718SPierre Ossman host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW, 6061c6a0718SPierre Ossman pxamci_dma_irq, host); 6071c6a0718SPierre Ossman if (host->dma < 0) { 6081c6a0718SPierre Ossman ret = -EBUSY; 6091c6a0718SPierre Ossman goto out; 6101c6a0718SPierre Ossman } 6111c6a0718SPierre Ossman 6121c6a0718SPierre Ossman ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); 6131c6a0718SPierre Ossman if (ret) 6141c6a0718SPierre Ossman goto out; 6151c6a0718SPierre Ossman 6161c6a0718SPierre Ossman platform_set_drvdata(pdev, mmc); 6171c6a0718SPierre Ossman 6189a788c6bSBridge Wu dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); 6199a788c6bSBridge Wu if (!dmarx) { 6209a788c6bSBridge Wu ret = -ENXIO; 6219a788c6bSBridge Wu goto out; 6229a788c6bSBridge Wu } 6239a788c6bSBridge Wu host->dma_drcmrrx = dmarx->start; 6249a788c6bSBridge Wu 6259a788c6bSBridge Wu dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); 6269a788c6bSBridge Wu if (!dmatx) { 6279a788c6bSBridge Wu ret = -ENXIO; 6289a788c6bSBridge Wu goto out; 6299a788c6bSBridge Wu } 6309a788c6bSBridge Wu host->dma_drcmrtx = dmatx->start; 6319a788c6bSBridge Wu 6321c6a0718SPierre Ossman if (host->pdata && host->pdata->init) 6331c6a0718SPierre Ossman host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); 6341c6a0718SPierre Ossman 6351c6a0718SPierre Ossman mmc_add_host(mmc); 6361c6a0718SPierre Ossman 6371c6a0718SPierre Ossman return 0; 6381c6a0718SPierre Ossman 6391c6a0718SPierre Ossman out: 6401c6a0718SPierre Ossman if (host) { 6411c6a0718SPierre Ossman if (host->dma >= 0) 6421c6a0718SPierre Ossman pxa_free_dma(host->dma); 6431c6a0718SPierre Ossman if (host->base) 6441c6a0718SPierre Ossman iounmap(host->base); 6451c6a0718SPierre Ossman if (host->sg_cpu) 6461c6a0718SPierre Ossman dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 647ebebd9b0SRussell King if (host->clk) 648ebebd9b0SRussell King clk_put(host->clk); 6491c6a0718SPierre Ossman } 6501c6a0718SPierre Ossman if (mmc) 6511c6a0718SPierre Ossman mmc_free_host(mmc); 6521c6a0718SPierre Ossman release_resource(r); 6531c6a0718SPierre Ossman return ret; 6541c6a0718SPierre Ossman } 6551c6a0718SPierre Ossman 6561c6a0718SPierre Ossman static int pxamci_remove(struct platform_device *pdev) 6571c6a0718SPierre Ossman { 6581c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(pdev); 6591c6a0718SPierre Ossman 6601c6a0718SPierre Ossman platform_set_drvdata(pdev, NULL); 6611c6a0718SPierre Ossman 6621c6a0718SPierre Ossman if (mmc) { 6631c6a0718SPierre Ossman struct pxamci_host *host = mmc_priv(mmc); 6641c6a0718SPierre Ossman 6651c6a0718SPierre Ossman if (host->pdata && host->pdata->exit) 6661c6a0718SPierre Ossman host->pdata->exit(&pdev->dev, mmc); 6671c6a0718SPierre Ossman 6681c6a0718SPierre Ossman mmc_remove_host(mmc); 6691c6a0718SPierre Ossman 6701c6a0718SPierre Ossman pxamci_stop_clock(host); 6711c6a0718SPierre Ossman writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| 6721c6a0718SPierre Ossman END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, 6731c6a0718SPierre Ossman host->base + MMC_I_MASK); 6741c6a0718SPierre Ossman 6759a788c6bSBridge Wu DRCMR(host->dma_drcmrrx) = 0; 6769a788c6bSBridge Wu DRCMR(host->dma_drcmrtx) = 0; 6771c6a0718SPierre Ossman 6781c6a0718SPierre Ossman free_irq(host->irq, host); 6791c6a0718SPierre Ossman pxa_free_dma(host->dma); 6801c6a0718SPierre Ossman iounmap(host->base); 6811c6a0718SPierre Ossman dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 6821c6a0718SPierre Ossman 683ebebd9b0SRussell King clk_put(host->clk); 684ebebd9b0SRussell King 6851c6a0718SPierre Ossman release_resource(host->res); 6861c6a0718SPierre Ossman 6871c6a0718SPierre Ossman mmc_free_host(mmc); 6881c6a0718SPierre Ossman } 6891c6a0718SPierre Ossman return 0; 6901c6a0718SPierre Ossman } 6911c6a0718SPierre Ossman 6921c6a0718SPierre Ossman #ifdef CONFIG_PM 6931c6a0718SPierre Ossman static int pxamci_suspend(struct platform_device *dev, pm_message_t state) 6941c6a0718SPierre Ossman { 6951c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(dev); 6961c6a0718SPierre Ossman int ret = 0; 6971c6a0718SPierre Ossman 6981c6a0718SPierre Ossman if (mmc) 6991c6a0718SPierre Ossman ret = mmc_suspend_host(mmc, state); 7001c6a0718SPierre Ossman 7011c6a0718SPierre Ossman return ret; 7021c6a0718SPierre Ossman } 7031c6a0718SPierre Ossman 7041c6a0718SPierre Ossman static int pxamci_resume(struct platform_device *dev) 7051c6a0718SPierre Ossman { 7061c6a0718SPierre Ossman struct mmc_host *mmc = platform_get_drvdata(dev); 7071c6a0718SPierre Ossman int ret = 0; 7081c6a0718SPierre Ossman 7091c6a0718SPierre Ossman if (mmc) 7101c6a0718SPierre Ossman ret = mmc_resume_host(mmc); 7111c6a0718SPierre Ossman 7121c6a0718SPierre Ossman return ret; 7131c6a0718SPierre Ossman } 7141c6a0718SPierre Ossman #else 7151c6a0718SPierre Ossman #define pxamci_suspend NULL 7161c6a0718SPierre Ossman #define pxamci_resume NULL 7171c6a0718SPierre Ossman #endif 7181c6a0718SPierre Ossman 7191c6a0718SPierre Ossman static struct platform_driver pxamci_driver = { 7201c6a0718SPierre Ossman .probe = pxamci_probe, 7211c6a0718SPierre Ossman .remove = pxamci_remove, 7221c6a0718SPierre Ossman .suspend = pxamci_suspend, 7231c6a0718SPierre Ossman .resume = pxamci_resume, 7241c6a0718SPierre Ossman .driver = { 7251c6a0718SPierre Ossman .name = DRIVER_NAME, 726bc65c724SKay Sievers .owner = THIS_MODULE, 7271c6a0718SPierre Ossman }, 7281c6a0718SPierre Ossman }; 7291c6a0718SPierre Ossman 7301c6a0718SPierre Ossman static int __init pxamci_init(void) 7311c6a0718SPierre Ossman { 7321c6a0718SPierre Ossman return platform_driver_register(&pxamci_driver); 7331c6a0718SPierre Ossman } 7341c6a0718SPierre Ossman 7351c6a0718SPierre Ossman static void __exit pxamci_exit(void) 7361c6a0718SPierre Ossman { 7371c6a0718SPierre Ossman platform_driver_unregister(&pxamci_driver); 7381c6a0718SPierre Ossman } 7391c6a0718SPierre Ossman 7401c6a0718SPierre Ossman module_init(pxamci_init); 7411c6a0718SPierre Ossman module_exit(pxamci_exit); 7421c6a0718SPierre Ossman 7431c6a0718SPierre Ossman MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); 7441c6a0718SPierre Ossman MODULE_LICENSE("GPL"); 745bc65c724SKay Sievers MODULE_ALIAS("platform:pxa2xx-mci"); 746