mmci.c revision 771dc157e06d69fcece0b2c8a29b9010345d8e9a
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. 564de028948f449af17cf387f45a45f36ffd3c960Linus Walleij * Copyright (C) 2010 ST-Ericsson AB. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/highmem.h> 20019a5f56ec195aceadada18aaaad0f67294bdaefNicolas Pitre#include <linux/log2.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h> 22a62c80e559809e6c7851ec04d30575e85ad6f6edRussell King#include <linux/amba/bus.h> 23f8ce25476d5f12ffa29b885e49c38cd95053437eRussell King#include <linux/clk.h> 24bd6dee6f30a0f6943df190b387b5f8fe98a848f3Jens Axboe#include <linux/scatterlist.h> 2589001446925d6da8785c3265a71316e34c6d15deRussell King#include <linux/gpio.h> 266ef297f86b62f187c59475784208f75c2ed8ccd8Linus Walleij#include <linux/amba/mmci.h> 2734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#include <linux/regulator/consumer.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29e9c091b47409255cefa1672041479d850b7b991aRussell King#include <asm/cacheflush.h> 307b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King#include <asm/div64.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 32c6b8fdad144bbb915d124ffd95011ad55730bf9fRussell King#include <asm/sizes.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mmci.h" 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "mmci-pl18x" 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int fmax = 515633; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij/* 41a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij * This must be called with host->lock held 42a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij */ 43a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleijstatic void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) 44a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij{ 45a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij u32 clk = 0; 46a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij 47a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij if (desired) { 48a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij if (desired >= host->mclk) { 49a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij clk = MCI_CLK_BYPASS; 50a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij host->cclk = host->mclk; 51a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij } else { 52a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij clk = host->mclk / (2 * desired) - 1; 53a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij if (clk >= 256) 54a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij clk = 255; 55a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij host->cclk = host->mclk / (2 * (clk + 1)); 56a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij } 57b43149c168ce4069ce8828b1ceb8f7eb42bc4b82Linus Walleij if (host->hw_designer == AMBA_VENDOR_ST) 58771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */ 59a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij clk |= MCI_CLK_ENABLE; 60a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij /* This hasn't proven to be worthwhile */ 61a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij /* clk |= MCI_CLK_PWRSAVE; */ 62a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij } 63a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij 649e6c82cd3e1a739ef48bf8c1decc8e7a7d8de3acLinus Walleij if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) 65771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij clk |= MCI_4BIT_BUS; 66771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) 67771dc157e06d69fcece0b2c8a29b9010345d8e9aLinus Walleij clk |= MCI_ST_8BIT_BUS; 689e6c82cd3e1a739ef48bf8c1decc8e7a7d8de3acLinus Walleij 69a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij writel(clk, host->base + MMCICLOCK); 70a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij} 71a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_request_end(struct mmci_host *host, struct mmc_request *mrq) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCICOMMAND); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King BUG_ON(host->data); 78e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = NULL; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->data->bytes_xfered = host->data_xfered; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Need to drop the host lock here; mmc_request_done may call 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * back into the driver... 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_request_done(host->mmc, mrq); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_stop_data(struct mmci_host *host) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIDATACTRL); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = NULL; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_start_data(struct mmci_host *host, struct mmc_data *data) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int datactrl, timeout, irqmask; 1047b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King unsigned long long clks; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base; 1063bc87f243f64c953717bea058f4b458a57fc1a29Russell King int blksz_bits; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10864de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n", 10964de028948f449af17cf387f45a45f36ffd3c960Linus Walleij data->blksz, data->blocks, data->flags); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = data; 1123bc87f243f64c953717bea058f4b458a57fc1a29Russell King host->size = data->blksz; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data_xfered = 0; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_init_sg(host, data); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1177b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King clks = (unsigned long long)data->timeout_ns * host->cclk; 1187b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King do_div(clks, 1000000000UL); 1197b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King 1207b09cdac5af1e13ab4b30421ae5c4b7953c26841Russell King timeout = data->timeout_clks + (unsigned int)clks; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = host->base; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(timeout, base + MMCIDATATIMER); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(host->size, base + MMCIDATALENGTH); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1263bc87f243f64c953717bea058f4b458a57fc1a29Russell King blksz_bits = ffs(data->blksz) - 1; 1273bc87f243f64c953717bea058f4b458a57fc1a29Russell King BUG_ON(1 << blksz_bits != data->blksz); 1283bc87f243f64c953717bea058f4b458a57fc1a29Russell King 1293bc87f243f64c953717bea058f4b458a57fc1a29Russell King datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_READ) { 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datactrl |= MCI_DPSM_DIRECTION; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irqmask = MCI_RXFIFOHALFFULLMASK; 1330425a14213f373595bd23cacdc675f2b973a28d4Russell King 1340425a14213f373595bd23cacdc675f2b973a28d4Russell King /* 1350425a14213f373595bd23cacdc675f2b973a28d4Russell King * If we have less than a FIFOSIZE of bytes to transfer, 1360425a14213f373595bd23cacdc675f2b973a28d4Russell King * trigger a PIO interrupt as soon as any data is available. 1370425a14213f373595bd23cacdc675f2b973a28d4Russell King */ 1380425a14213f373595bd23cacdc675f2b973a28d4Russell King if (host->size < MCI_FIFOSIZE) 1390425a14213f373595bd23cacdc675f2b973a28d4Russell King irqmask |= MCI_RXDATAAVLBLMASK; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't actually need to include "FIFO empty" here 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since its implicit in "FIFO half empty". 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irqmask = MCI_TXFIFOHALFEMPTYMASK; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(datactrl, base + MMCIDATACTRL); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(irqmask, base + MMCIMASK1); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15864de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->opcode, cmd->arg, cmd->flags); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, base + MMCICOMMAND); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= cmd->opcode | MCI_CPSM_ENABLE; 167e92251762d02a46177d4105d1744041e3f8bc465Russell King if (cmd->flags & MMC_RSP_PRESENT) { 168e92251762d02a46177d4105d1744041e3f8bc465Russell King if (cmd->flags & MMC_RSP_136) 169e92251762d02a46177d4105d1744041e3f8bc465Russell King c |= MCI_CPSM_LONGRSP; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= MCI_CPSM_RESPONSE; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (/*interrupt*/0) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c |= MCI_CPSM_INTERRUPT; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = cmd; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(cmd->arg, base + MMCIARGUMENT); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(c, base + MMCICOMMAND); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_data_irq(struct mmci_host *host, struct mmc_data *data, 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATABLOCKEND) { 1863bc87f243f64c953717bea058f4b458a57fc1a29Russell King host->data_xfered += data->blksz; 187f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij#ifdef CONFIG_ARCH_U300 188f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij /* 189f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij * On the U300 some signal or other is 190f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij * badly routed so that a data write does 191f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij * not properly terminate with a MCI_DATAEND 192f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij * status flag. This quirk will make writes 193f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij * work again. 194f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij */ 195f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij if (data->flags & MMC_DATA_WRITE) 196f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij status |= MCI_DATAEND; 197f28e8a4d027e4e21c3d0a52706527bb87397bea0Linus Walleij#endif 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { 20064de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATACRCFAIL) 20217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EILSEQ; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & MCI_DATATIMEOUT) 20417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -ETIMEDOUT; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) 20617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EIO; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status |= MCI_DATAEND; 208e9c091b47409255cefa1672041479d850b7b991aRussell King 209e9c091b47409255cefa1672041479d850b7b991aRussell King /* 210e9c091b47409255cefa1672041479d850b7b991aRussell King * We hit an error condition. Ensure that any data 211e9c091b47409255cefa1672041479d850b7b991aRussell King * partially written to a page is properly coherent. 212e9c091b47409255cefa1672041479d850b7b991aRussell King */ 213e9c091b47409255cefa1672041479d850b7b991aRussell King if (host->sg_len && data->flags & MMC_DATA_READ) 214bd6dee6f30a0f6943df190b387b5f8fe98a848f3Jens Axboe flush_dcache_page(sg_page(host->sg_ptr)); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_DATAEND) { 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_stop_data(host); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->stop) { 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_request_end(host, data->mrq); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_command(host, data->stop, 0); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[0] = readl(base + MMCIRESPONSE0); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[1] = readl(base + MMCIRESPONSE1); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[2] = readl(base + MMCIRESPONSE2); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[3] = readl(base + MMCIRESPONSE3); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_CMDTIMEOUT) { 24117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -ETIMEDOUT; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { 24317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -EILSEQ; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (!cmd->data || cmd->error) { 247e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King if (host->data) 248e47c222b22cd53c317a5573e1dc5f9e0cbd46380Russell King mmci_stop_data(host); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_request_end(host, cmd->mrq); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!(cmd->data->flags & MMC_DATA_READ)) { 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_data(host, cmd->data); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ptr = buffer; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 26026eed9a5c61edd93d88e147188d4feae6770174eLinus Walleij int host_remain = host->size; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 26326eed9a5c61edd93d88e147188d4feae6770174eLinus Walleij int count = host_remain - (readl(base + MMCIFIFOCNT) << 2); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > remain) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = remain; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count <= 0) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds readsl(base + MMCIFIFO, ptr, count >> 2); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += count; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= count; 27526eed9a5c61edd93d88e147188d4feae6770174eLinus Walleij host_remain -= count; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain == 0) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & MCI_RXDATAAVLBL); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ptr - buffer; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ptr = buffer; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count, maxcnt; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = min(remain, maxcnt); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writesl(base + MMCIFIFO, ptr, count >> 2); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr += count; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= count; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain == 0) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status & MCI_TXFIFOHALFEMPTY); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ptr - buffer; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PIO data transfer IRQ handler. 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3147d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mmci_pio_irq(int irq, void *dev_id) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = dev_id; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base = host->base; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32264de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int remain, len; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buffer; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For write, we only need to test the half-empty flag 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here - if the FIFO is completely empty, then by 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * definition it is more than half empty. 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For read, check for data available. 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Map the current scatter buffer. 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain = host->sg_ptr->length - host->sg_off; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 0; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_RXACTIVE) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = mmci_pio_read(host, buffer, remain); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_TXACTIVE) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = mmci_pio_write(host, buffer, remain, status); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unmap the buffer. 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 354f3e2628bed0d5a88ced8239b35f1534557f9631cEvgeniy Polyakov mmci_kunmap_atomic(host, buffer, &flags); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_off += len; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->size -= len; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remain -= len; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (remain) 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 363e9c091b47409255cefa1672041479d850b7b991aRussell King /* 364e9c091b47409255cefa1672041479d850b7b991aRussell King * If we were reading, and we have completed this 365e9c091b47409255cefa1672041479d850b7b991aRussell King * page, ensure that the data cache is coherent. 366e9c091b47409255cefa1672041479d850b7b991aRussell King */ 367e9c091b47409255cefa1672041479d850b7b991aRussell King if (status & MCI_RXACTIVE) 368bd6dee6f30a0f6943df190b387b5f8fe98a848f3Jens Axboe flush_dcache_page(sg_page(host->sg_ptr)); 369e9c091b47409255cefa1672041479d850b7b991aRussell King 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmci_next_sg(host)) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(base + MMCISTATUS); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (1); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're nearing the end of the read, switch to 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "any data available" mode. 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE) 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we run out of data, disable the data IRQs; this 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prevents a race where the FIFO becomes empty before 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the chip itself has disabled the data path, and 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stops us racing with our data end IRQ. 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->size == 0) { 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, base + MMCIMASK1); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle completion of command and data transfers. 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4007d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mmci_irq(int irq, void *dev_id) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = dev_id; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&host->lock); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command *cmd; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_data *data; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = readl(host->base + MMCISTATUS); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= readl(host->base + MMCIMASK0); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(status, host->base + MMCICLEAR); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41664de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = host->data; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_data_irq(host, data, status); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = host->cmd; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_cmd_irq(host, cmd, status); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 1; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (status); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&host->lock); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(ret); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 4389e9430213f85ebdaf40026ec790295420efd0f91Linus Walleij unsigned long flags; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(host->mrq != NULL); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 442019a5f56ec195aceadada18aaaad0f67294bdaefNicolas Pitre if (mrq->data && !is_power_of_2(mrq->data->blksz)) { 44364de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n", 44464de028948f449af17cf387f45a45f36ffd3c960Linus Walleij mrq->data->blksz); 445255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman mrq->cmd->error = -EINVAL; 446255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman mmc_request_done(mmc, mrq); 447255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman return; 448255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman } 449255d01af9a990fd5166f04ed0cc0b30b7b67e81ePierre Ossman 4509e9430213f85ebdaf40026ec790295420efd0f91Linus Walleij spin_lock_irqsave(&host->lock, flags); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = mrq; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data && mrq->data->flags & MMC_DATA_READ) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_data(host, mrq->data); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmci_start_command(host, mrq->cmd, 0); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4599e9430213f85ebdaf40026ec790295420efd0f91Linus Walleij spin_unlock_irqrestore(&host->lock, flags); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 465a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij u32 pwr = 0; 466a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij unsigned long flags; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ios->power_mode) { 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_OFF: 47034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if(host->vcc && 47134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij regulator_is_enabled(host->vcc)) 47234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij regulator_disable(host->vcc); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_UP: 47534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#ifdef CONFIG_REGULATOR 47634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if (host->vcc) 47734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij /* This implicitly enables the regulator */ 47834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij mmc_regulator_set_ocr(host->vcc, ios->vdd); 47934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#endif 48034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij /* 48134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij * The translate_vdd function is not used if you have 48234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij * an external regulator, or your design is really weird. 48334e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij * Using it would mean sending in power control BOTH using 48434e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij * a regulator AND the 4 MMCIPWR bits. If we don't have 48534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij * a regulator, we might have some other platform specific 48634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij * power control behind this translate function. 48734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij */ 48834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if (!host->vcc && host->plat->translate_vdd) 48934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); 490cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij /* The ST version does not have this, fall through to POWER_ON */ 491f17a1f06d2fa93f4825be572622eb02c4894db4eLinus Walleij if (host->hw_designer != AMBA_VENDOR_ST) { 492cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij pwr |= MCI_PWR_UP; 493cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij break; 494cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij } 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MMC_POWER_ON: 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pwr |= MCI_PWR_ON; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 500cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { 501f17a1f06d2fa93f4825be572622eb02c4894db4eLinus Walleij if (host->hw_designer != AMBA_VENDOR_ST) 502cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij pwr |= MCI_ROD; 503cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij else { 504cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij /* 505cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij * The ST Micro variant use the ROD bit for something 506cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij * else and only has OD (Open Drain). 507cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij */ 508cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij pwr |= MCI_OD; 509cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij } 510cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij } 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 512a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij spin_lock_irqsave(&host->lock, flags); 513a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij 514a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij mmci_set_clkreg(host, ios->clock); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->pwr != pwr) { 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->pwr = pwr; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(pwr, host->base + MMCIPOWER); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 520a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij 521a6a6464a0ecd20c5f1594a4fe5b24af6181b7366Linus Walleij spin_unlock_irqrestore(&host->lock, flags); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52489001446925d6da8785c3265a71316e34c6d15deRussell Kingstatic int mmci_get_ro(struct mmc_host *mmc) 52589001446925d6da8785c3265a71316e34c6d15deRussell King{ 52689001446925d6da8785c3265a71316e34c6d15deRussell King struct mmci_host *host = mmc_priv(mmc); 52789001446925d6da8785c3265a71316e34c6d15deRussell King 52889001446925d6da8785c3265a71316e34c6d15deRussell King if (host->gpio_wp == -ENOSYS) 52989001446925d6da8785c3265a71316e34c6d15deRussell King return -ENOSYS; 53089001446925d6da8785c3265a71316e34c6d15deRussell King 53189001446925d6da8785c3265a71316e34c6d15deRussell King return gpio_get_value(host->gpio_wp); 53289001446925d6da8785c3265a71316e34c6d15deRussell King} 53389001446925d6da8785c3265a71316e34c6d15deRussell King 53489001446925d6da8785c3265a71316e34c6d15deRussell Kingstatic int mmci_get_cd(struct mmc_host *mmc) 53589001446925d6da8785c3265a71316e34c6d15deRussell King{ 53689001446925d6da8785c3265a71316e34c6d15deRussell King struct mmci_host *host = mmc_priv(mmc); 53789001446925d6da8785c3265a71316e34c6d15deRussell King unsigned int status; 53889001446925d6da8785c3265a71316e34c6d15deRussell King 53989001446925d6da8785c3265a71316e34c6d15deRussell King if (host->gpio_cd == -ENOSYS) 54089001446925d6da8785c3265a71316e34c6d15deRussell King status = host->plat->status(mmc_dev(host->mmc)); 54189001446925d6da8785c3265a71316e34c6d15deRussell King else 54289001446925d6da8785c3265a71316e34c6d15deRussell King status = gpio_get_value(host->gpio_cd); 54389001446925d6da8785c3265a71316e34c6d15deRussell King 54489001446925d6da8785c3265a71316e34c6d15deRussell King return !status; 54589001446925d6da8785c3265a71316e34c6d15deRussell King} 54689001446925d6da8785c3265a71316e34c6d15deRussell King 547ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops mmci_ops = { 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .request = mmci_request, 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_ios = mmci_set_ios, 55089001446925d6da8785c3265a71316e34c6d15deRussell King .get_ro = mmci_get_ro, 55189001446925d6da8785c3265a71316e34c6d15deRussell King .get_cd = mmci_get_cd, 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmci_check_status(unsigned long data) 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = (struct mmci_host *)data; 55789001446925d6da8785c3265a71316e34c6d15deRussell King unsigned int status = mmci_get_cd(host->mmc); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status ^ host->oldstat) 5608dc003359cc3996abad9e53a7b2280b272610283Richard Purdie mmc_detect_change(host->mmc, 0); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->oldstat = status; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&host->timer, jiffies + HZ); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56603fbdb15c14e9746c63168e3ff2c64b9c8336d33Alessandro Rubinistatic int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5686ef297f86b62f187c59475784208f75c2ed8ccd8Linus Walleij struct mmci_platform_data *plat = dev->dev.platform_data; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* must have platform data */ 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!plat) { 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = amba_request_regions(dev, DRIVER_NAME); 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmc) { 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto rel_regions; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = mmc_priv(mmc); 5904ea580f1db62c5419e6690878fd61a740f3aae8eRabin Vincent host->mmc = mmc; 591012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King 59289001446925d6da8785c3265a71316e34c6d15deRussell King host->gpio_wp = -ENOSYS; 59389001446925d6da8785c3265a71316e34c6d15deRussell King host->gpio_cd = -ENOSYS; 59489001446925d6da8785c3265a71316e34c6d15deRussell King 595012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King host->hw_designer = amba_manf(dev); 596012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King host->hw_revision = amba_rev(dev); 59764de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer); 59864de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision); 599012b7d339ce8c42d41e35b35c4acc3dd29501d52Russell King 600ee569c43e340202fb0ba427c57b77568a32b9a3aRussell King host->clk = clk_get(&dev->dev, NULL); 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(host->clk)) { 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = PTR_ERR(host->clk); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->clk = NULL; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto host_free; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = clk_enable(host->clk); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 609a8d3584a2df28827094f6338cde1303c467bc1f0Russell King goto clk_free; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->plat = plat; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mclk = clk_get_rate(host->clk); 613c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij /* 614c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij * According to the spec, mclk is max 100 MHz, 615c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij * so we try to adjust the clock down to this, 616c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij * (if possible). 617c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij */ 618c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij if (host->mclk > 100000000) { 619c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij ret = clk_set_rate(host->clk, 100000000); 620c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij if (ret < 0) 621c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij goto clk_disable; 622c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij host->mclk = clk_get_rate(host->clk); 62364de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", 62464de028948f449af17cf387f45a45f36ffd3c960Linus Walleij host->mclk); 625c8df9a53e8d16877fc0b268b002af2a47a14643aLinus Walleij } 626dc890c2dcd63a90de68ee5f0253eefbb89d725f0Linus Walleij host->base = ioremap(dev->res.start, resource_size(&dev->res)); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->base) { 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto clk_disable; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->ops = &mmci_ops; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->f_min = (host->mclk + 511) / 512; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->f_max = min(host->mclk, fmax); 63564de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); 63664de028948f449af17cf387f45a45f36ffd3c960Linus Walleij 63734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#ifdef CONFIG_REGULATOR 63834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij /* If we're using the regulator framework, try to fetch a regulator */ 63934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij host->vcc = regulator_get(&dev->dev, "vmmc"); 64034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if (IS_ERR(host->vcc)) 64134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij host->vcc = NULL; 64234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij else { 64334e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij int mask = mmc_regulator_get_ocrmask(host->vcc); 64434e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij 64534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if (mask < 0) 64634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij dev_err(&dev->dev, "error getting OCR mask (%d)\n", 64734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij mask); 64834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij else { 64934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij host->mmc->ocr_avail = (u32) mask; 65034e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if (plat->ocr_mask) 65134e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij dev_warn(&dev->dev, 65234e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij "Provided ocr_mask/setpower will not be used " 65334e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij "(using regulator instead)\n"); 65434e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij } 65534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij } 65634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij#endif 65734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij /* Fall back to platform data if no regulator is found */ 65834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if (host->vcc == NULL) 65934e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij mmc->ocr_avail = plat->ocr_mask; 6609e6c82cd3e1a739ef48bf8c1decc8e7a7d8de3acLinus Walleij mmc->caps = plat->capabilities; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can do SGIO 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_hw_segs = 16; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_phys_segs = NR_SG; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since we only have a 16-bit data length register, we must 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ensure that we don't exceed 2^16-1 bytes in a single request. 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_req_size = 65535; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the maximum segment size. Since we aren't doing DMA 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (yet) we are only limited by the data length register. 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 67855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_seg_size = mmc->max_req_size; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 680fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman /* 681fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman * Block size can be up to 2048 bytes, but must be a power of two. 682fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman */ 683fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman mmc->max_blk_size = 2048; 684fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 68555db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman /* 68655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * No limit on the number of blocks transferred. 68755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman */ 68855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_blk_count = mmc->max_req_size; 68955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&host->lock); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0xfff, host->base + MMCICLEAR); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69689001446925d6da8785c3265a71316e34c6d15deRussell King if (gpio_is_valid(plat->gpio_cd)) { 69789001446925d6da8785c3265a71316e34c6d15deRussell King ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); 69889001446925d6da8785c3265a71316e34c6d15deRussell King if (ret == 0) 69989001446925d6da8785c3265a71316e34c6d15deRussell King ret = gpio_direction_input(plat->gpio_cd); 70089001446925d6da8785c3265a71316e34c6d15deRussell King if (ret == 0) 70189001446925d6da8785c3265a71316e34c6d15deRussell King host->gpio_cd = plat->gpio_cd; 70289001446925d6da8785c3265a71316e34c6d15deRussell King else if (ret != -ENOSYS) 70389001446925d6da8785c3265a71316e34c6d15deRussell King goto err_gpio_cd; 70489001446925d6da8785c3265a71316e34c6d15deRussell King } 70589001446925d6da8785c3265a71316e34c6d15deRussell King if (gpio_is_valid(plat->gpio_wp)) { 70689001446925d6da8785c3265a71316e34c6d15deRussell King ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); 70789001446925d6da8785c3265a71316e34c6d15deRussell King if (ret == 0) 70889001446925d6da8785c3265a71316e34c6d15deRussell King ret = gpio_direction_input(plat->gpio_wp); 70989001446925d6da8785c3265a71316e34c6d15deRussell King if (ret == 0) 71089001446925d6da8785c3265a71316e34c6d15deRussell King host->gpio_wp = plat->gpio_wp; 71189001446925d6da8785c3265a71316e34c6d15deRussell King else if (ret != -ENOSYS) 71289001446925d6da8785c3265a71316e34c6d15deRussell King goto err_gpio_wp; 71389001446925d6da8785c3265a71316e34c6d15deRussell King } 71489001446925d6da8785c3265a71316e34c6d15deRussell King 715dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto unmap; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 719dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto irq0_free; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_IRQENABLE, host->base + MMCIMASK0); 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, mmc); 72689001446925d6da8785c3265a71316e34c6d15deRussell King host->oldstat = mmci_get_cd(host->mmc); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_add_host(mmc); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73064de028948f449af17cf387f45a45f36ffd3c960Linus Walleij dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n", 731d366b6436386875b1310ce8f70e3f9dea4647bacRussell King mmc_hostname(mmc), amba_rev(dev), amba_config(dev), 732e29419fffceb8ec36def3c922040e1ca7bcd3de5Greg Kroah-Hartman (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&host->timer); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.data = (unsigned long)host; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.function = mmci_check_status; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->timer.expires = jiffies + HZ; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&host->timer); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq0_free: 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[0], host); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unmap: 74589001446925d6da8785c3265a71316e34c6d15deRussell King if (host->gpio_wp != -ENOSYS) 74689001446925d6da8785c3265a71316e34c6d15deRussell King gpio_free(host->gpio_wp); 74789001446925d6da8785c3265a71316e34c6d15deRussell King err_gpio_wp: 74889001446925d6da8785c3265a71316e34c6d15deRussell King if (host->gpio_cd != -ENOSYS) 74989001446925d6da8785c3265a71316e34c6d15deRussell King gpio_free(host->gpio_cd); 75089001446925d6da8785c3265a71316e34c6d15deRussell King err_gpio_cd: 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable: 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(host->clk); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_free: 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(host->clk); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_free: 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rel_regions: 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_release_regions(dev); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7646dc4a47a0cf423879b505af0e29997fca4088630Linus Walleijstatic int __devexit mmci_remove(struct amba_device *dev) 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_set_drvdata(dev, NULL); 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&host->timer); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_remove_host(mmc); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK1); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCICOMMAND); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIDATACTRL); 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[0], host); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq[1], host); 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78689001446925d6da8785c3265a71316e34c6d15deRussell King if (host->gpio_wp != -ENOSYS) 78789001446925d6da8785c3265a71316e34c6d15deRussell King gpio_free(host->gpio_wp); 78889001446925d6da8785c3265a71316e34c6d15deRussell King if (host->gpio_cd != -ENOSYS) 78989001446925d6da8785c3265a71316e34c6d15deRussell King gpio_free(host->gpio_cd); 79089001446925d6da8785c3265a71316e34c6d15deRussell King 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_disable(host->clk); 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clk_put(host->clk); 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79534e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij if (regulator_is_enabled(host->vcc)) 79634e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij regulator_disable(host->vcc); 79734e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij regulator_put(host->vcc); 79834e84f39a27d059a3e6ec6e8b94aafa702e6f220Linus Walleij 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_release_regions(dev); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 808e5378ca8c0ab684bd9339dc6827dd5a042f9e6fcPavel Machekstatic int mmci_suspend(struct amba_device *dev, pm_message_t state) 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mmc_suspend_host(mmc, state); 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == 0) 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMCIMASK0); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmci_resume(struct amba_device *dev) 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc = amba_get_drvdata(dev); 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmci_host *host = mmc_priv(mmc); 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(MCI_IRQENABLE, host->base + MMCIMASK0); 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mmc_resume_host(mmc); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_suspend NULL 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmci_resume NULL 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_id mmci_ids[] = { 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = 0x00041180, 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0x000fffff, 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = 0x00041181, 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0x000fffff, 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 853cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij /* ST Micro variants */ 854cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij { 855cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij .id = 0x00180180, 856cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij .mask = 0x00ffffff, 857cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij }, 858cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij { 859cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij .id = 0x00280180, 860cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij .mask = 0x00ffffff, 861cc30d60e4ca0b68e7e3f906eddd1e5b995d349f8Linus Walleij }, 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, 0 }, 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct amba_driver mmci_driver = { 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = DRIVER_NAME, 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = mmci_probe, 8706dc4a47a0cf423879b505af0e29997fca4088630Linus Walleij .remove = __devexit_p(mmci_remove), 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .suspend = mmci_suspend, 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .resume = mmci_resume, 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = mmci_ids, 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init mmci_init(void) 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return amba_driver_register(&mmci_driver); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit mmci_exit(void) 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amba_driver_unregister(&mmci_driver); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mmci_init); 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mmci_exit); 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(fmax, uint, 0444); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 892