mmci.c revision f8ce25476d5f12ffa29b885e49c38cd95053437e
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/highmem.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/protocol.h> 22a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/bus.h> 23f8ce25476d5f12ffa29b885e49c38cd95053437eRussell King#include <linux/clk.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 257b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King#include <asm/div64.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/scatterlist.h> 28c6b8fdad144bbb915d124ffd95011ad55730bf9fRussell King#include <asm/sizes.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach/mmc.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mmci.h" 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "mmci-pl18x" 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MMC_DEBUG 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(host,fmt,args...) \ 37d366b6436386875b1310ce8f70e3f9dea4647bacRussell King pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(host,fmt,args...) do { } while (0) 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int fmax = 515633; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_request_end(struct mmci_host *host, struct mmc_request *mrq) 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCICOMMAND); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = NULL; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data) 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->data->bytes_xfered = host->data_xfered; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Need to drop the host lock here; mmc_request_done may call 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * back into the driver... 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_request_done(host->mmc, mrq); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_stop_data(struct mmci_host *host) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIDATACTRL); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = NULL; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_start_data(struct mmci_host *host, struct mmc_data *data) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int datactrl, timeout, irqmask; 747b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King unsigned long long clks; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "blksz %04x blks %04x flags %08x\n", 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1 << data->blksz_bits, data->blocks, data->flags); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = data; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->size = data->blocks << data->blksz_bits; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data_xfered = 0; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_init_sg(host, data); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 867b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King clks = (unsigned long long)data->timeout_ns * host->cclk; 877b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King do_div(clks, 1000000000UL); 887b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King 897b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King timeout = data->timeout_clks + (unsigned int)clks; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = host->base; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(timeout, base + MMCIDATATIMER); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(host->size, base + MMCIDATALENGTH); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_READ) { 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datactrl |= MCI_DPSM_DIRECTION; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irqmask = MCI_RXFIFOHALFFULLMASK; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't actually need to include "FIFO empty" here 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since its implicit in "FIFO half empty". 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irqmask = MCI_TXFIFOHALFEMPTYMASK; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(datactrl, base + MMCIDATACTRL); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(irqmask, base + MMCIMASK1); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "op %02x arg %08x flags %08x\n", 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->opcode, cmd->arg, cmd->flags); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, base + MMCICOMMAND); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= cmd->opcode | MCI_CPSM_ENABLE; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd->flags & MMC_RSP_MASK) { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_RSP_NONE: 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_RSP_LONG: 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= MCI_CPSM_LONGRSP; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_RSP_SHORT: 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= MCI_CPSM_RESPONSE; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (/*interrupt*/0) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= MCI_CPSM_INTERRUPT; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = cmd; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(cmd->arg, base + MMCIARGUMENT); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(c, base + MMCICOMMAND); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_data_irq(struct mmci_host *host, struct mmc_data *data, 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATABLOCKEND) { 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data_xfered += 1 << data->blksz_bits; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATACRCFAIL) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->error = MMC_ERR_BADCRC; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & MCI_DATATIMEOUT) 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->error = MMC_ERR_TIMEOUT; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->error = MMC_ERR_FIFO; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status |= MCI_DATAEND; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATAEND) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_stop_data(host); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->stop) { 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_request_end(host, data->mrq); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_command(host, data->stop, 0); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[0] = readl(base + MMCIRESPONSE0); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[1] = readl(base + MMCIRESPONSE1); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[2] = readl(base + MMCIRESPONSE2); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[3] = readl(base + MMCIRESPONSE3); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_CMDTIMEOUT) { 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->error = MMC_ERR_TIMEOUT; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->error = MMC_ERR_BADCRC; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cmd->data || cmd->error != MMC_ERR_NONE) { 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_request_end(host, cmd->mrq); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!(cmd->data->flags & MMC_DATA_READ)) { 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_data(host, cmd->data); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ptr = buffer; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count = host->size - (readl(base + MMCIFIFOCNT) << 2); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > remain) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = remain; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count <= 0) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds readsl(base + MMCIFIFO, ptr, count >> 2); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += count; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= count; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain == 0) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & MCI_RXDATAAVLBL); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ptr - buffer; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ptr = buffer; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count, maxcnt; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = min(remain, maxcnt); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writesl(base + MMCIFIFO, ptr, count >> 2); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += count; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= count; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain == 0) 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & MCI_TXFIFOHALFEMPTY); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ptr - buffer; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PIO data transfer IRQ handler. 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = dev_id; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "irq1 %08x\n", status); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int remain, len; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buffer; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For write, we only need to test the half-empty flag 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here - if the FIFO is completely empty, then by 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * definition it is more than half empty. 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For read, check for data available. 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Map the current scatter buffer. 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain = host->sg_ptr->length - host->sg_off; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 0; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_RXACTIVE) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = mmci_pio_read(host, buffer, remain); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_TXACTIVE) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = mmci_pio_write(host, buffer, remain, status); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unmap the buffer. 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_kunmap_atomic(host, &flags); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_off += len; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->size -= len; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= len; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmci_next_sg(host)) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (1); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're nearing the end of the read, switch to 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "any data available" mode. 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we run out of data, disable the data IRQs; this 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prevents a race where the FIFO becomes empty before 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the chip itself has disabled the data path, and 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stops us racing with our data end IRQ. 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->size == 0) { 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, base + MMCIMASK1); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle completion of command and data transfers. 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = dev_id; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command *cmd; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_data *data; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(host->base + MMCISTATUS); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= readl(host->base + MMCIMASK0); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(status, host->base + MMCICLEAR); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "irq0 %08x\n", status); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = host->data; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_data_irq(host, data, status); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = host->cmd; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_cmd_irq(host, cmd, status); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 1; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(ret); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(host->mrq != NULL); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&host->lock); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = mrq; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data && mrq->data->flags & MMC_DATA_READ) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_data(host, mrq->data); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_command(host, mrq->cmd, 0); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&host->lock); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clk = 0, pwr = 0; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n", 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->clock) { 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->clock >= host->mclk) { 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = MCI_CLK_BYPASS; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cclk = host->mclk; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = host->mclk / (2 * ios->clock) - 1; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clk > 256) 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = 255; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cclk = host->mclk / (2 * (clk + 1)); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk |= MCI_CLK_ENABLE; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->plat->translate_vdd) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ios->power_mode) { 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_OFF: 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_UP: 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= MCI_PWR_UP; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_ON: 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= MCI_PWR_ON; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= MCI_ROD; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(clk, host->base + MMCICLOCK); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->pwr != pwr) { 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->pwr = pwr; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(pwr, host->base + MMCIPOWER); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_host_ops mmci_ops = { 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .request = mmci_request, 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_ios = mmci_set_ios, 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_check_status(unsigned long data) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = (struct mmci_host *)data; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = host->plat->status(mmc_dev(host->mmc)); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status ^ host->oldstat) 4458dc003359cc3996abad9e53a7b2280b272610283Richard Purdie mmc_detect_change(host->mmc, 0); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->oldstat = status; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&host->timer, jiffies + HZ); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_probe(struct amba_device *dev, void *id) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_platform_data *plat = dev->dev.platform_data; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* must have platform data */ 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!plat) { 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = amba_request_regions(dev, DRIVER_NAME); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmc) { 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto rel_regions; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = mmc_priv(mmc); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->clk = clk_get(&dev->dev, "MCLK"); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(host->clk)) { 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(host->clk); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->clk = NULL; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto host_free; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = clk_enable(host->clk); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 484a8d3584a2df28827094f6338cde1303c467bc1f0Russell King goto clk_free; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->plat = plat; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mclk = clk_get_rate(host->clk); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mmc = mmc; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->base = ioremap(dev->res.start, SZ_4K); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->base) { 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto clk_disable; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->ops = &mmci_ops; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->f_min = (host->mclk + 511) / 512; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->f_max = min(host->mclk, fmax); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->ocr_avail = plat->ocr_mask; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can do SGIO 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_hw_segs = 16; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_phys_segs = NR_SG; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since we only have a 16-bit data length register, we must 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that we don't exceed 2^16-1 bytes in a single request. 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Choose 64 (512-byte) sectors as the limit. 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_sectors = 64; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the maximum segment size. Since we aren't doing DMA 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (yet) we are only limited by the data length register. 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_seg_size = mmc->max_sectors << 9; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&host->lock); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0xfff, host->base + MMCICLEAR); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto unmap; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = request_irq(dev->irq[1], mmci_pio_irq, SA_SHIRQ, DRIVER_NAME " (pio)", host); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto irq0_free; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_IRQENABLE, host->base + MMCIMASK0); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, mmc); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_add_host(mmc); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n", 540d366b6436386875b1310ce8f70e3f9dea4647bacRussell King mmc_hostname(mmc), amba_rev(dev), amba_config(dev), 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->res.start, dev->irq[0], dev->irq[1]); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&host->timer); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.data = (unsigned long)host; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.function = mmci_check_status; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.expires = jiffies + HZ; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&host->timer); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq0_free: 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[0], host); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unmap: 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable: 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(host->clk); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_free: 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(host->clk); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_free: 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rel_regions: 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_release_regions(dev); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_remove(struct amba_device *dev) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, NULL); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&host->timer); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_remove_host(mmc); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCICOMMAND); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIDATACTRL); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[0], host); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[1], host); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(host->clk); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(host->clk); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_release_regions(dev); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 602e5378ca8c0ab684bd9339dc6827dd5a042f9e6fcPavel Machekstatic int mmci_suspend(struct amba_device *dev, pm_message_t state) 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mmc_suspend_host(mmc, state); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == 0) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_resume(struct amba_device *dev) 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_IRQENABLE, host->base + MMCIMASK0); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mmc_resume_host(mmc); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_suspend NULL 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_resume NULL 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_id mmci_ids[] = { 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = 0x00041180, 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0x000fffff, 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = 0x00041181, 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0x000fffff, 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, 0 }, 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_driver mmci_driver = { 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = DRIVER_NAME, 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = mmci_probe, 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = mmci_remove, 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .suspend = mmci_suspend, 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .resume = mmci_resume, 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = mmci_ids, 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init mmci_init(void) 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return amba_driver_register(&mmci_driver); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit mmci_exit(void) 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_driver_unregister(&mmci_driver); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mmci_init); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mmci_exit); 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(fmax, uint, 0444); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 677