mmci.c revision 17b0429dde9ab60f9cee8e07ab28c7dc6cfe6efd
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 270f10482c668301c483acded13bf68780ad352b9Pierre Ossman * linux/drivers/mmc/host/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/module.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/highmem.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h> 20a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/bus.h> 21f8ce25476d5f12ffa29b885e49c38cd95053437eRussell King#include <linux/clk.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23e9c091b47409255cefa1672041479d850b7b991aRussell King#include <asm/cacheflush.h> 247b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King#include <asm/div64.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/scatterlist.h> 27c6b8fdad144bbb915d124ffd95011ad55730bf9fRussell King#include <asm/sizes.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach/mmc.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mmci.h" 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "mmci-pl18x" 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(host,fmt,args...) \ 35d366b6436386875b1310ce8f70e3f9dea4647bacRussell King pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int fmax = 515633; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_request_end(struct mmci_host *host, struct mmc_request *mrq) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCICOMMAND); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King BUG_ON(host->data); 45e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = NULL; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data) 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->data->bytes_xfered = host->data_xfered; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Need to drop the host lock here; mmc_request_done may call 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * back into the driver... 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_request_done(host->mmc, mrq); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_stop_data(struct mmci_host *host) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIDATACTRL); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = NULL; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_start_data(struct mmci_host *host, struct mmc_data *data) 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int datactrl, timeout, irqmask; 717b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King unsigned long long clks; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base; 733bc87f243f64c953717bea058f4b458a57fc1a29Russell King int blksz_bits; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "blksz %04x blks %04x flags %08x\n", 763bc87f243f64c953717bea058f4b458a57fc1a29Russell King data->blksz, data->blocks, data->flags); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = data; 793bc87f243f64c953717bea058f4b458a57fc1a29Russell King host->size = data->blksz; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data_xfered = 0; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_init_sg(host, data); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 847b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King clks = (unsigned long long)data->timeout_ns * host->cclk; 857b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King do_div(clks, 1000000000UL); 867b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King 877b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King timeout = data->timeout_clks + (unsigned int)clks; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = host->base; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(timeout, base + MMCIDATATIMER); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(host->size, base + MMCIDATALENGTH); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 933bc87f243f64c953717bea058f4b458a57fc1a29Russell King blksz_bits = ffs(data->blksz) - 1; 943bc87f243f64c953717bea058f4b458a57fc1a29Russell King BUG_ON(1 << blksz_bits != data->blksz); 953bc87f243f64c953717bea058f4b458a57fc1a29Russell King 963bc87f243f64c953717bea058f4b458a57fc1a29Russell King datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_READ) { 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datactrl |= MCI_DPSM_DIRECTION; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irqmask = MCI_RXFIFOHALFFULLMASK; 1000425a14213f373595bd23cacdc675f2b973a28d4Russell King 1010425a14213f373595bd23cacdc675f2b973a28d4Russell King /* 1020425a14213f373595bd23cacdc675f2b973a28d4Russell King * If we have less than a FIFOSIZE of bytes to transfer, 1030425a14213f373595bd23cacdc675f2b973a28d4Russell King * trigger a PIO interrupt as soon as any data is available. 1040425a14213f373595bd23cacdc675f2b973a28d4Russell King */ 1050425a14213f373595bd23cacdc675f2b973a28d4Russell King if (host->size < MCI_FIFOSIZE) 1060425a14213f373595bd23cacdc675f2b973a28d4Russell King irqmask |= MCI_RXDATAAVLBLMASK; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't actually need to include "FIFO empty" here 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since its implicit in "FIFO half empty". 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irqmask = MCI_TXFIFOHALFEMPTYMASK; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(datactrl, base + MMCIDATACTRL); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(irqmask, base + MMCIMASK1); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "op %02x arg %08x flags %08x\n", 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->opcode, cmd->arg, cmd->flags); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, base + MMCICOMMAND); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= cmd->opcode | MCI_CPSM_ENABLE; 134e92251762d02a46177d4105d1744041e3f8bc465Russell King if (cmd->flags & MMC_RSP_PRESENT) { 135e92251762d02a46177d4105d1744041e3f8bc465Russell King if (cmd->flags & MMC_RSP_136) 136e92251762d02a46177d4105d1744041e3f8bc465Russell King c |= MCI_CPSM_LONGRSP; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= MCI_CPSM_RESPONSE; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (/*interrupt*/0) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= MCI_CPSM_INTERRUPT; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = cmd; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(cmd->arg, base + MMCIARGUMENT); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(c, base + MMCICOMMAND); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_data_irq(struct mmci_host *host, struct mmc_data *data, 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATABLOCKEND) { 1533bc87f243f64c953717bea058f4b458a57fc1a29Russell King host->data_xfered += data->blksz; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATACRCFAIL) 15717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EILSEQ; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & MCI_DATATIMEOUT) 15917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -ETIMEDOUT; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) 16117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EIO; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status |= MCI_DATAEND; 163e9c091b47409255cefa1672041479d850b7b991aRussell King 164e9c091b47409255cefa1672041479d850b7b991aRussell King /* 165e9c091b47409255cefa1672041479d850b7b991aRussell King * We hit an error condition. Ensure that any data 166e9c091b47409255cefa1672041479d850b7b991aRussell King * partially written to a page is properly coherent. 167e9c091b47409255cefa1672041479d850b7b991aRussell King */ 168e9c091b47409255cefa1672041479d850b7b991aRussell King if (host->sg_len && data->flags & MMC_DATA_READ) 169e9c091b47409255cefa1672041479d850b7b991aRussell King flush_dcache_page(host->sg_ptr->page); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATAEND) { 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_stop_data(host); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->stop) { 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_request_end(host, data->mrq); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_command(host, data->stop, 0); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[0] = readl(base + MMCIRESPONSE0); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[1] = readl(base + MMCIRESPONSE1); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[2] = readl(base + MMCIRESPONSE2); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[3] = readl(base + MMCIRESPONSE3); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_CMDTIMEOUT) { 19617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -ETIMEDOUT; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { 19817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EILSEQ; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (!cmd->data || cmd->error) { 202e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King if (host->data) 203e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King mmci_stop_data(host); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_request_end(host, cmd->mrq); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!(cmd->data->flags & MMC_DATA_READ)) { 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_data(host, cmd->data); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ptr = buffer; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count = host->size - (readl(base + MMCIFIFOCNT) << 2); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > remain) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = remain; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count <= 0) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds readsl(base + MMCIFIFO, ptr, count >> 2); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += count; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= count; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain == 0) 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & MCI_RXDATAAVLBL); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ptr - buffer; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ptr = buffer; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count, maxcnt; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = min(remain, maxcnt); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writesl(base + MMCIFIFO, ptr, count >> 2); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += count; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= count; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain == 0) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & MCI_TXFIFOHALFEMPTY); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ptr - buffer; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PIO data transfer IRQ handler. 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2677d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mmci_pio_irq(int irq, void *dev_id) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = dev_id; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "irq1 %08x\n", status); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int remain, len; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buffer; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For write, we only need to test the half-empty flag 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here - if the FIFO is completely empty, then by 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * definition it is more than half empty. 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For read, check for data available. 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Map the current scatter buffer. 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain = host->sg_ptr->length - host->sg_off; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 0; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_RXACTIVE) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = mmci_pio_read(host, buffer, remain); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_TXACTIVE) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = mmci_pio_write(host, buffer, remain, status); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unmap the buffer. 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 307f3e2628bed0d5a88ced8239b35f1534557f9631cEvgeniy Polyakov mmci_kunmap_atomic(host, buffer, &flags); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_off += len; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->size -= len; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= len; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 316e9c091b47409255cefa1672041479d850b7b991aRussell King /* 317e9c091b47409255cefa1672041479d850b7b991aRussell King * If we were reading, and we have completed this 318e9c091b47409255cefa1672041479d850b7b991aRussell King * page, ensure that the data cache is coherent. 319e9c091b47409255cefa1672041479d850b7b991aRussell King */ 320e9c091b47409255cefa1672041479d850b7b991aRussell King if (status & MCI_RXACTIVE) 321e9c091b47409255cefa1672041479d850b7b991aRussell King flush_dcache_page(host->sg_ptr->page); 322e9c091b47409255cefa1672041479d850b7b991aRussell King 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmci_next_sg(host)) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (1); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're nearing the end of the read, switch to 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "any data available" mode. 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we run out of data, disable the data IRQs; this 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prevents a race where the FIFO becomes empty before 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the chip itself has disabled the data path, and 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stops us racing with our data end IRQ. 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->size == 0) { 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, base + MMCIMASK1); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle completion of command and data transfers. 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3537d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mmci_irq(int irq, void *dev_id) 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = dev_id; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command *cmd; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_data *data; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(host->base + MMCISTATUS); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= readl(host->base + MMCIMASK0); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(status, host->base + MMCICLEAR); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(host, "irq0 %08x\n", status); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = host->data; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_data_irq(host, data, status); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = host->cmd; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_cmd_irq(host, cmd, status); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 1; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(ret); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(host->mrq != NULL); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&host->lock); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = mrq; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data && mrq->data->flags & MMC_DATA_READ) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_data(host, mrq->data); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_command(host, mrq->cmd, 0); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&host->lock); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clk = 0, pwr = 0; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->clock) { 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->clock >= host->mclk) { 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = MCI_CLK_BYPASS; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cclk = host->mclk; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = host->mclk / (2 * ios->clock) - 1; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clk > 256) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk = 255; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cclk = host->mclk / (2 * (clk + 1)); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk |= MCI_CLK_ENABLE; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->plat->translate_vdd) 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ios->power_mode) { 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_OFF: 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_UP: 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= MCI_PWR_UP; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_ON: 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= MCI_PWR_ON; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= MCI_ROD; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(clk, host->base + MMCICLOCK); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->pwr != pwr) { 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->pwr = pwr; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(pwr, host->base + MMCIPOWER); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 449ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops mmci_ops = { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .request = mmci_request, 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_ios = mmci_set_ios, 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_check_status(unsigned long data) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = (struct mmci_host *)data; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = host->plat->status(mmc_dev(host->mmc)); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status ^ host->oldstat) 4618dc003359cc3996abad9e53a7b2280b272610283Richard Purdie mmc_detect_change(host->mmc, 0); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->oldstat = status; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&host->timer, jiffies + HZ); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_probe(struct amba_device *dev, void *id) 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_platform_data *plat = dev->dev.platform_data; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* must have platform data */ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!plat) { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = amba_request_regions(dev, DRIVER_NAME); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmc) { 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto rel_regions; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = mmc_priv(mmc); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->clk = clk_get(&dev->dev, "MCLK"); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(host->clk)) { 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(host->clk); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->clk = NULL; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto host_free; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = clk_enable(host->clk); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 500a8d3584a2df28827094f6338cde1303c467bc1f0Russell King goto clk_free; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->plat = plat; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mclk = clk_get_rate(host->clk); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mmc = mmc; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->base = ioremap(dev->res.start, SZ_4K); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->base) { 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto clk_disable; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->ops = &mmci_ops; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->f_min = (host->mclk + 511) / 512; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->f_max = min(host->mclk, fmax); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->ocr_avail = plat->ocr_mask; 515db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King mmc->caps = MMC_CAP_MULTIWRITE; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can do SGIO 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_hw_segs = 16; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_phys_segs = NR_SG; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since we only have a 16-bit data length register, we must 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that we don't exceed 2^16-1 bytes in a single request. 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_req_size = 65535; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the maximum segment size. Since we aren't doing DMA 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (yet) we are only limited by the data length register. 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53355db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_seg_size = mmc->max_req_size; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 535fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman /* 536fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * Block size can be up to 2048 bytes, but must be a power of two. 537fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman */ 538fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman mmc->max_blk_size = 2048; 539fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 54055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman /* 54155db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * No limit on the number of blocks transferred. 54255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman */ 54355db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_blk_count = mmc->max_req_size; 54455db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&host->lock); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0xfff, host->base + MMCICLEAR); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto unmap; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 555dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto irq0_free; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_IRQENABLE, host->base + MMCIMASK0); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, mmc); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_add_host(mmc); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 565e29419fffceb8ec36def3c922040e1ca7bcd3de5Greg Kroah-Hartman printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n", 566d366b6436386875b1310ce8f70e3f9dea4647bacRussell King mmc_hostname(mmc), amba_rev(dev), amba_config(dev), 567e29419fffceb8ec36def3c922040e1ca7bcd3de5Greg Kroah-Hartman (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&host->timer); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.data = (unsigned long)host; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.function = mmci_check_status; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.expires = jiffies + HZ; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&host->timer); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq0_free: 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[0], host); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unmap: 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable: 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(host->clk); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_free: 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(host->clk); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_free: 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rel_regions: 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_release_regions(dev); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_remove(struct amba_device *dev) 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, NULL); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&host->timer); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_remove_host(mmc); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCICOMMAND); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIDATACTRL); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[0], host); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[1], host); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(host->clk); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(host->clk); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_release_regions(dev); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 628e5378ca8c0ab684bd9339dc6827dd5a042f9e6fcPavel Machekstatic int mmci_suspend(struct amba_device *dev, pm_message_t state) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mmc_suspend_host(mmc, state); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == 0) 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_resume(struct amba_device *dev) 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_IRQENABLE, host->base + MMCIMASK0); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mmc_resume_host(mmc); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_suspend NULL 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_resume NULL 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_id mmci_ids[] = { 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = 0x00041180, 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0x000fffff, 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = 0x00041181, 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0x000fffff, 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, 0 }, 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_driver mmci_driver = { 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = DRIVER_NAME, 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = mmci_probe, 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = mmci_remove, 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .suspend = mmci_suspend, 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .resume = mmci_resume, 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = mmci_ids, 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init mmci_init(void) 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return amba_driver_register(&mmci_driver); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit mmci_exit(void) 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_driver_unregister(&mmci_driver); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mmci_init); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mmci_exit); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(fmax, uint, 0444); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 703