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