11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 270f10482c668301c483acded13bf68780ad352b9Pierre Ossman * linux/drivers/mmc/host/pxa.c - PXA MMCI driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Russell King, 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 * This hardware is really sick: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - No way to clear interrupts. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Have to turn off the clock whenever we touch the device. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Doesn't tell you how many data blocks were transferred. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Yuck! 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1 and 3 byte data transfers not supported 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * max block length up to 1023 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 22d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h> 26ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King#include <linux/clk.h> 27ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King#include <linux/err.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h> 2905678a96de2e97fdfd4b817478840ad6a02ea1d8Russell King#include <linux/io.h> 308385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro#include <linux/regulator/consumer.h> 31b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik#include <linux/gpio.h> 325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sizes.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3605678a96de2e97fdfd4b817478840ad6a02ea1d8Russell King#include <mach/hardware.h> 377ebc8d56f407184a457dd5fc739cf39e423a25aaEric Miao#include <mach/dma.h> 38a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/mmc.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pxamci.h" 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "pxa2xx-mci" 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NR_SG 1 45d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King#define CLKRT_OFF (~0) 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang#define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310() \ 48fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang || cpu_is_pxa935()) 49fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pxamci_host { 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource *res; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base; 55ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King struct clk *clk; 56ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King unsigned long clkrate; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dma; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int clkrt; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmdat; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int imask; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int power_mode; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pxamci_platform_data *pdata; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_request *mrq; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command *cmd; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_data *data; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t sg_dma; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pxa_dma_desc *sg_cpu; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int dma_len; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int dma_dir; 749a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu unsigned int dma_drcmrrx; 759a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu unsigned int dma_drcmrtx; 768385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro 778385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro struct regulator *vcc; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 808385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeirostatic inline void pxamci_init_ocr(struct pxamci_host *host) 818385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro{ 828385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro#ifdef CONFIG_REGULATOR 838385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); 848385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro 858385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro if (IS_ERR(host->vcc)) 868385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro host->vcc = NULL; 878385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro else { 888385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); 898385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro if (host->pdata && host->pdata->ocr_mask) 908385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro dev_warn(mmc_dev(host->mmc), 918385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro "ocr_mask/setpower will not be used\n"); 928385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro } 938385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro#endif 948385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro if (host->vcc == NULL) { 958385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro /* fall-back to platform data */ 968385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro host->mmc->ocr_avail = host->pdata ? 978385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro host->pdata->ocr_mask : 988385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro MMC_VDD_32_33 | MMC_VDD_33_34; 998385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro } 1008385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro} 1018385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro 10299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleijstatic inline int pxamci_set_power(struct pxamci_host *host, 10399fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij unsigned char power_mode, 10499fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij unsigned int vdd) 1058385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro{ 106b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik int on; 107b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik 10899fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij if (host->vcc) { 10999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij int ret; 11099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij 11199fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij if (power_mode == MMC_POWER_UP) { 11299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); 11399fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij if (ret) 11499fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij return ret; 11599fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij } else if (power_mode == MMC_POWER_OFF) { 11699fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); 11799fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij if (ret) 11899fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij return ret; 11999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij } 12099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij } 121b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (!host->vcc && host->pdata && 122b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_is_valid(host->pdata->gpio_power)) { 123b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik on = ((1 << vdd) & host->pdata->ocr_mask); 124b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_set_value(host->pdata->gpio_power, 125b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik !!on ^ host->pdata->gpio_power_invert); 126b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 1278385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro if (!host->vcc && host->pdata && host->pdata->setpower) 1288385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro host->pdata->setpower(mmc_dev(host->mmc), vdd); 12999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij 13099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij return 0; 1318385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro} 1328385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_stop_clock(struct pxamci_host *host) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long timeout = 10000; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int v; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(STOP_CLOCK, host->base + MMC_STRPCL); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = readl(host->base + MMC_STAT); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(v & STAT_CLK_EN)) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (timeout--); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (v & STAT_CLK_EN) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&host->lock, flags); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->imask &= ~mask; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(host->imask, host->base + MMC_I_MASK); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&host->lock, flags); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&host->lock, flags); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->imask |= mask; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(host->imask, host->base + MMC_I_MASK); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&host->lock, flags); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nob = data->blocks; 1763d63abe56be2147891b3438cb3bd37a9be72bda7Russell King unsigned long long clks; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int timeout; 17897f8571e663c808ad2d01a396627235167291556Philipp Zabel bool dalgn = 0; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dcmd; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = data; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_STREAM) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nob = 0xffff; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(nob, host->base + MMC_NOB); 1882c171bf13423dc5293188cea7f6c2da1720926e2Pavel Pisa writel(data->blksz, host->base + MMC_BLKLEN); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 190ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King clks = (unsigned long long)data->timeout_ns * host->clkrate; 1913d63abe56be2147891b3438cb3bd37a9be72bda7Russell King do_div(clks, 1000000000UL); 1923d63abe56be2147891b3438cb3bd37a9be72bda7Russell King timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel((timeout + 255) / 256, host->base + MMC_RDTO); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_READ) { 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma_dir = DMA_FROM_DEVICE; 1977eeff4814224646c896303ba2c2b7ac3c4240cd2Matt Reimer dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC; 1989a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu DRCMR(host->dma_drcmrtx) = 0; 1999a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma_dir = DMA_TO_DEVICE; 2027eeff4814224646c896303ba2c2b7ac3c4240cd2Matt Reimer dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; 2039a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu DRCMR(host->dma_drcmrrx) = 0; 2049a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dcmd |= DCMD_BURST32 | DCMD_WIDTH1; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma_dir); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < host->dma_len; i++) { 213c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre unsigned int length = sg_dma_len(&data->sg[i]); 214c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre host->sg_cpu[i].dcmd = dcmd | length; 215c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre if (length & 31 && !(data->flags & MMC_DATA_READ)) 216c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; 21797f8571e663c808ad2d01a396627235167291556Philipp Zabel /* Not aligned to 8-byte boundary? */ 21897f8571e663c808ad2d01a396627235167291556Philipp Zabel if (sg_dma_address(&data->sg[i]) & 0x7) 21997f8571e663c808ad2d01a396627235167291556Philipp Zabel dalgn = 1; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->flags & MMC_DATA_READ) { 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct pxa_dma_desc); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wmb(); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23397f8571e663c808ad2d01a396627235167291556Philipp Zabel /* 23497f8571e663c808ad2d01a396627235167291556Philipp Zabel * The PXA27x DMA controller encounters overhead when working with 23597f8571e663c808ad2d01a396627235167291556Philipp Zabel * unaligned (to 8-byte boundaries) data, so switch on byte alignment 23697f8571e663c808ad2d01a396627235167291556Philipp Zabel * mode only if we have unaligned data. 23797f8571e663c808ad2d01a396627235167291556Philipp Zabel */ 23897f8571e663c808ad2d01a396627235167291556Philipp Zabel if (dalgn) 23997f8571e663c808ad2d01a396627235167291556Philipp Zabel DALGN |= (1 << host->dma); 24097f8571e663c808ad2d01a396627235167291556Philipp Zabel else 2414fe16897c59882420d66f2d503106653d026ed6cKarl Beldan DALGN &= ~(1 << host->dma); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DDADR(host->dma) = host->sg_dma; 243b6018958a57f6621d6979c4384e42a3df636beedCliff Brake 244b6018958a57f6621d6979c4384e42a3df636beedCliff Brake /* 245b6018958a57f6621d6979c4384e42a3df636beedCliff Brake * workaround for erratum #91: 246b6018958a57f6621d6979c4384e42a3df636beedCliff Brake * only start DMA now if we are doing a read, 247b6018958a57f6621d6979c4384e42a3df636beedCliff Brake * otherwise we wait until CMD/RESP has finished 248b6018958a57f6621d6979c4384e42a3df636beedCliff Brake * before starting DMA. 249b6018958a57f6621d6979c4384e42a3df636beedCliff Brake */ 250b6018958a57f6621d6979c4384e42a3df636beedCliff Brake if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) 251b6018958a57f6621d6979c4384e42a3df636beedCliff Brake DCSR(host->dma) = DCSR_RUN; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(host->cmd != NULL); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = cmd; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->flags & MMC_RSP_BUSY) 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat |= CMDAT_BUSY; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 262e92251762d02a46177d4105d1744041e3f8bc465Russell King#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) 263e92251762d02a46177d4105d1744041e3f8bc465Russell King switch (RSP_TYPE(mmc_resp_type(cmd))) { 2646f949909e8f9e5d7e5584dc48d9a5e060c52aed1Philip Langdale case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat |= CMDAT_RESP_SHORT; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 267e92251762d02a46177d4105d1744041e3f8bc465Russell King case RSP_TYPE(MMC_RSP_R3): 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat |= CMDAT_RESP_R3; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 270e92251762d02a46177d4105d1744041e3f8bc465Russell King case RSP_TYPE(MMC_RSP_R2): 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat |= CMDAT_RESP_R2; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(cmd->opcode, host->base + MMC_CMD); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(cmd->arg >> 16, host->base + MMC_ARGH); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(cmd->arg & 0xffff, host->base + MMC_ARGL); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(cmdat, host->base + MMC_CMDAT); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(host->clkrt, host->base + MMC_CLKRT); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(START_CLOCK, host->base + MMC_STRPCL); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_enable_irq(host, END_CMD_RES); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = NULL; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = NULL; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_request_done(host->mmc, mrq); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command *cmd = host->cmd; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 v; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cmd) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmd = NULL; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Did I mention this is Sick. We always need to 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * discard the upper 8 bits of the first 16-bit word. 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = readl(host->base + MMC_RES) & 0xffff; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 4; i++) { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 w1 = readl(host->base + MMC_RES) & 0xffff; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 w2 = readl(host->base + MMC_RES) & 0xffff; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = w2; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat & STAT_TIME_OUT_RESPONSE) { 32017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman cmd->error = -ETIMEDOUT; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * workaround for erratum #42: 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Intel PXA27x Family Processor Specification Update Rev 001 32590e07d9f54c61449dd48eff82e2354d0124d4f7eNicolas Pitre * A bogus CRC error can appear if the msb of a 136 bit 32690e07d9f54c61449dd48eff82e2354d0124d4f7eNicolas Pitre * response is a one. 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 328e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake if (cpu_is_pxa27x() && 329e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000)) 33090e07d9f54c61449dd48eff82e2354d0124d4f7eNicolas Pitre pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); 331e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake else 332e10a854c4602072c34c03380b99da0a3ee15682cCliff Brake cmd->error = -EILSEQ; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_disable_irq(host, END_CMD_RES); 33617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (host->data && !cmd->error) { 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_enable_irq(host, DATA_TRAN_DONE); 338b6018958a57f6621d6979c4384e42a3df636beedCliff Brake /* 339b6018958a57f6621d6979c4384e42a3df636beedCliff Brake * workaround for erratum #91, if doing write 340b6018958a57f6621d6979c4384e42a3df636beedCliff Brake * enable DMA late 341b6018958a57f6621d6979c4384e42a3df636beedCliff Brake */ 342b6018958a57f6621d6979c4384e42a3df636beedCliff Brake if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) 343b6018958a57f6621d6979c4384e42a3df636beedCliff Brake DCSR(host->dma) = DCSR_RUN; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_finish_request(host, host->mrq); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pxamci_data_done(struct pxamci_host *host, unsigned int stat) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_data *data = host->data; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DCSR(host->dma) = 0; 359c00a46abd4d45a67ff62f4ff6d4f839dff38b877Vernon Sauder dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma_dir); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat & STAT_READ_TIME_OUT) 36317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -ETIMEDOUT; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) 36517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman data->error = -EILSEQ; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There appears to be a hardware design bug here. There seems to 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be no way to find out how much data was transferred to the card. 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This means that if there was an error on any block, we mark all 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data blocks as being in error. 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (!data->error) 3742c171bf13423dc5293188cea7f6c2da1720926e2Pavel Pisa data->bytes_xfered = data->blocks * data->blksz; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->bytes_xfered = 0; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_disable_irq(host, DATA_TRAN_DONE); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->data = NULL; 38158741e8b3603e56c3699550e8bc89cb136329343Russell King if (host->mrq->stop) { 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_stop_clock(host); 383df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu pxamci_start_cmd(host, host->mrq->stop, host->cmdat); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_finish_request(host, host->mrq); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3917d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pxamci_irq(int irq, void *devid) 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pxamci_host *host = devid; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ireg; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int handled = 0; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39781ab570f65395f09962f4bca0d89403f8911c071Bridge Wu ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ireg) { 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned stat = readl(host->base + MMC_STAT); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 402d78e9079af7526c4661ff484322094832776ef41Russell King pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ireg & END_CMD_RES) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled |= pxamci_cmd_done(host, stat); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ireg & DATA_TRAN_DONE) 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled |= pxamci_data_done(host, stat); 4085d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu if (ireg & SDIO_INT) { 4095d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu mmc_signal_sdio_irq(host->mmc); 4105d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu handled = 1; 4115d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu } 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(handled); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pxamci_host *host = mmc_priv(mmc); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmdat; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(host->mrq != NULL); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mrq = mrq; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_stop_clock(host); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat = host->cmdat; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmdat &= ~CMDAT_INIT; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data) { 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_setup_data(host, mrq->data); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat &= ~CMDAT_BUSY; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data->flags & MMC_DATA_WRITE) 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat |= CMDAT_WRITE; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data->flags & MMC_DATA_STREAM) 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmdat |= CMDAT_STREAM; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_start_cmd(host, mrq->cmd, cmdat); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 446e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdiestatic int pxamci_get_ro(struct mmc_host *mmc) 447e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie{ 448e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie struct pxamci_host *host = mmc_priv(mmc); 449e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie 450b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) { 451b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (host->pdata->gpio_card_ro_invert) 452b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik return !gpio_get_value(host->pdata->gpio_card_ro); 453b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik else 454b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik return gpio_get_value(host->pdata->gpio_card_ro); 455b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 456e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie if (host->pdata && host->pdata->get_ro) 45708f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov return !!host->pdata->get_ro(mmc_dev(mmc)); 45808f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov /* 45908f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov * Board doesn't support read only detection; let the mmc core 46008f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov * decide what to do. 46108f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov */ 46208f80bb5196517a0dfe50dc7c10f234c0ff2f0e8Anton Vorontsov return -ENOSYS; 463e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie} 464e619524fe5f5b0c13db34ed0f6320d2dcccf6e8dRichard Purdie 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pxamci_host *host = mmc_priv(mmc); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->clock) { 470ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King unsigned long rate = host->clkrate; 471ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King unsigned int clk = rate / ios->clock; 472ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King 473d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King if (host->clkrt == CLKRT_OFF) 474d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King clk_enable(host->clk); 475d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King 47664eb036af42d3816364c4db49d93be3a4614389cBridge Wu if (ios->clock == 26000000) { 477fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang /* to support 26MHz */ 47864eb036af42d3816364c4db49d93be3a4614389cBridge Wu host->clkrt = 7; 47964eb036af42d3816364c4db49d93be3a4614389cBridge Wu } else { 48064eb036af42d3816364c4db49d93be3a4614389cBridge Wu /* to handle (19.5MHz, 26MHz) */ 48164eb036af42d3816364c4db49d93be3a4614389cBridge Wu if (!clk) 48264eb036af42d3816364c4db49d93be3a4614389cBridge Wu clk = 1; 48364eb036af42d3816364c4db49d93be3a4614389cBridge Wu 48464eb036af42d3816364c4db49d93be3a4614389cBridge Wu /* 48564eb036af42d3816364c4db49d93be3a4614389cBridge Wu * clk might result in a lower divisor than we 48664eb036af42d3816364c4db49d93be3a4614389cBridge Wu * desire. check for that condition and adjust 48764eb036af42d3816364c4db49d93be3a4614389cBridge Wu * as appropriate. 48864eb036af42d3816364c4db49d93be3a4614389cBridge Wu */ 48964eb036af42d3816364c4db49d93be3a4614389cBridge Wu if (rate / clk > ios->clock) 49064eb036af42d3816364c4db49d93be3a4614389cBridge Wu clk <<= 1; 49164eb036af42d3816364c4db49d93be3a4614389cBridge Wu host->clkrt = fls(clk) - 1; 49264eb036af42d3816364c4db49d93be3a4614389cBridge Wu } 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we write clkrt on the next command 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_stop_clock(host); 499d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King if (host->clkrt != CLKRT_OFF) { 500d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King host->clkrt = CLKRT_OFF; 501d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King clk_disable(host->clk); 502d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King } 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->power_mode != ios->power_mode) { 50699fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij int ret; 50799fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->power_mode = ios->power_mode; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij ret = pxamci_set_power(host, ios->power_mode, ios->vdd); 51199fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij if (ret) { 51299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij dev_err(mmc_dev(mmc), "unable to set power\n"); 51399fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij /* 51499fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij * The .set_ios() function in the mmc_host_ops 51599fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij * struct return void, and failing to set the 51699fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij * power should be rare so we print an error and 51799fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij * return here. 51899fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij */ 51999fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij return; 52099fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij } 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ios->power_mode == MMC_POWER_ON) 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->cmdat |= CMDAT_INIT; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 526df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu if (ios->bus_width == MMC_BUS_WIDTH_4) 527df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu host->cmdat |= CMDAT_SD_4DAT; 528df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu else 529df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu host->cmdat &= ~CMDAT_SD_4DAT; 530df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu 53199fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n", 53299fc5131018cbdc3cf42ce09fb394a4e8b053c74Linus Walleij host->clkrt, host->cmdat); 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5355d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wustatic void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) 5365d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu{ 5375d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu struct pxamci_host *pxa_host = mmc_priv(host); 5385d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu 5395d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu if (enable) 5405d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu pxamci_enable_irq(pxa_host, SDIO_INT); 5415d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu else 5425d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu pxamci_disable_irq(pxa_host, SDIO_INT); 5435d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu} 5445d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu 545ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops pxamci_ops = { 5465d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu .request = pxamci_request, 5475d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu .get_ro = pxamci_get_ro, 5485d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu .set_ios = pxamci_set_ios, 5495d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu .enable_sdio_irq = pxamci_enable_sdio_irq, 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5527d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pxamci_dma_irq(int dma, void *devid) 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 554c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre struct pxamci_host *host = devid; 555c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre int dcsr = DCSR(dma); 556c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; 557c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre 558c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre if (dcsr & DCSR_ENDINTR) { 559c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre writel(BUF_PART_FULL, host->base + MMC_PRTBUF); 560c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre } else { 561a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_err("%s: DMA error on channel %d (DCSR=%#x)\n", 562c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre mmc_hostname(host->mmc), dma, dcsr); 563c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre host->data->error = -EIO; 564c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre pxamci_data_done(host, 0); 565c783837bc69dd0f329a441c1704f5a02d01d1bd5Nicolas Pitre } 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5687d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pxamci_detect_irq(int irq, void *devid) 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 570c26971cbb39727b0b692c6236f890ba13046a663Richard Purdie struct pxamci_host *host = mmc_priv(devid); 571c26971cbb39727b0b692c6236f890ba13046a663Richard Purdie 572f97cab28b1895ecb0aa317cc785bb209f57fc1e8Eric Miao mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms)); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5763ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int pxamci_probe(struct platform_device *pdev) 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_host *mmc; 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pxamci_host *host = NULL; 5809a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu struct resource *r, *dmarx, *dmatx; 581b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = platform_get_irq(pdev, 0); 585489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel if (!r || irq < 0) 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!r) 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5923ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev); 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mmc) { 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->ops = &pxamci_ops; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can do SG-DMA, but we don't because we never know how much 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data we successfully wrote to the card. 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 604a36274e0184193e393fb82957925c3981a6b0477Martin K. Petersen mmc->max_segs = NR_SG; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Our hardware DMA can handle a maximum of one page per SG entry. 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc->max_seg_size = PAGE_SIZE; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman /* 612fe2dc44eac1223a0e92859242f58fd2a58a6f8faNicolas Pitre * Block length register is only 10 bits before PXA27x. 613fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman */ 6140ffcbfd54ea81ca24c0749f55ca4fcf3e2bdc23eEric Miao mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048; 615fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 61655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman /* 61755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman * Block count register is 16 bits. 61855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman */ 61955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman mmc->max_blk_count = 65535; 62055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = mmc_priv(mmc); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->mmc = mmc; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma = -1; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->pdata = pdev->dev.platform_data; 625d8cb70d10a2d4e6b083b89044a68d860d0bf1eecRussell King host->clkrt = CLKRT_OFF; 626ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King 627e0d8b13ae1e3ea747620580b6f777992148de182Russell King host->clk = clk_get(&pdev->dev, NULL); 628ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King if (IS_ERR(host->clk)) { 629ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King ret = PTR_ERR(host->clk); 630ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King host->clk = NULL; 631ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King goto out; 632ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King } 633ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King 634ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King host->clkrate = clk_get_rate(host->clk); 635ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King 636ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King /* 637ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King * Calculate minimum clock rate, rounding up. 638ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King */ 639ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King mmc->f_min = (host->clkrate + 63) / 64; 640fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate; 641ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King 6428385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro pxamci_init_ocr(host); 6438385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro 644df456f479aa6fdc812df51627c6f2c21d8a1aed8Bridge Wu mmc->caps = 0; 6455d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu host->cmdat = 0; 6460ffcbfd54ea81ca24c0749f55ca4fcf3e2bdc23eEric Miao if (!cpu_is_pxa25x()) { 6475d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; 6485d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu host->cmdat |= CMDAT_SDIO_INT_EN; 649fa3f99384c20751c66962848807403ff171dc02fHaojian Zhuang if (mmc_has_26MHz()) 65064eb036af42d3816364c4db49d93be3a4614389cBridge Wu mmc->caps |= MMC_CAP_MMC_HIGHSPEED | 65164eb036af42d3816364c4db49d93be3a4614389cBridge Wu MMC_CAP_SD_HIGHSPEED; 6525d3ad4e8a12e538eead0a37d22b1ba6aec0f2127Bridge Wu } 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6543ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->sg_cpu) { 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&host->lock); 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->res = r; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->irq = irq; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->imask = MMC_I_MASK_ALL; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->base = ioremap(r->start, SZ_4K); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->base) { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure that the host controller is shut down, and setup 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with our defaults. 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_stop_clock(host); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(0, host->base + MMC_SPI); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(64, host->base + MMC_RESTO); 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(host->imask, host->base + MMC_I_MASK); 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW, 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_dma_irq, host); 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->dma < 0) { 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EBUSY; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6913ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_set_drvdata(pdev, mmc); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6939a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); 6949a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu if (!dmarx) { 6959a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu ret = -ENXIO; 6969a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu goto out; 6979a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu } 6989a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu host->dma_drcmrrx = dmarx->start; 6999a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu 7009a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); 7019a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu if (!dmatx) { 7029a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu ret = -ENXIO; 7039a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu goto out; 7049a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu } 7059a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu host->dma_drcmrtx = dmatx->start; 7069a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu 707b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (host->pdata) { 708b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_cd = host->pdata->gpio_card_detect; 709b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_ro = host->pdata->gpio_card_ro; 710b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_power = host->pdata->gpio_power; 711b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 712b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_power)) { 713b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik ret = gpio_request(gpio_power, "mmc card power"); 714b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (ret) { 715b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power); 716b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik goto out; 717b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 718b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_direction_output(gpio_power, 719b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik host->pdata->gpio_power_invert); 720b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 721b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_ro)) { 722b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik ret = gpio_request(gpio_ro, "mmc card read only"); 723b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (ret) { 72448f029542f1219eb50ade5e24b1b2799bd057413Antonio Ospite dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro); 725b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik goto err_gpio_ro; 726b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 727b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_direction_input(gpio_ro); 728b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 729b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_cd)) { 730b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik ret = gpio_request(gpio_cd, "mmc card detect"); 731b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (ret) { 73248f029542f1219eb50ade5e24b1b2799bd057413Antonio Ospite dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd); 733b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik goto err_gpio_cd; 734b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 735b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_direction_input(gpio_cd); 736b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik 737b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq, 738b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 739b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik "mmc card detect", mmc); 740b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (ret) { 741b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik dev_err(&pdev->dev, "failed to request card detect IRQ\n"); 742b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik goto err_request_irq; 743b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 744b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 745b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->pdata && host->pdata->init) 7473ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 749b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_power) && host->pdata->setpower) 750b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n"); 751b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_ro) && host->pdata->get_ro) 752b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n"); 753b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_add_host(mmc); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 758b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmikerr_request_irq: 759b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_free(gpio_cd); 760b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmikerr_gpio_cd: 761b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_free(gpio_ro); 762b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmikerr_gpio_ro: 763b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_free(gpio_power); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host) { 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->dma >= 0) 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_free_dma(host->dma); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->base) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->sg_cpu) 7713ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 772ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King if (host->clk) 773ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King clk_put(host->clk); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resource(r); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7813ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int pxamci_remove(struct platform_device *pdev) 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7833ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King struct mmc_host *mmc = platform_get_drvdata(pdev); 784b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik int gpio_cd = -1, gpio_ro = -1, gpio_power = -1; 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7863ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_set_drvdata(pdev, NULL); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmc) { 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pxamci_host *host = mmc_priv(mmc); 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7915d6b1edf8ccc4b7e4e77dff3fc80882833d6186eDaniel Mack mmc_remove_host(mmc); 7925d6b1edf8ccc4b7e4e77dff3fc80882833d6186eDaniel Mack 793b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (host->pdata) { 794b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_cd = host->pdata->gpio_card_detect; 795b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_ro = host->pdata->gpio_card_ro; 796b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_power = host->pdata->gpio_power; 797b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 798b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_cd)) { 799b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik free_irq(gpio_to_irq(gpio_cd), mmc); 800b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_free(gpio_cd); 801b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik } 802b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_ro)) 803b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_free(gpio_ro); 804b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik if (gpio_is_valid(gpio_power)) 805b405db6c015fe8e4c9d8199a0355bb16d95d7049Robert Jarzmik gpio_free(gpio_power); 8068385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro if (host->vcc) 8078385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro regulator_put(host->vcc); 8088385f9cb7f12ef6a5261fa76f1a1b612280c94f7Daniel Ribeiro 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->pdata && host->pdata->exit) 8103ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King host->pdata->exit(&pdev->dev, mmc); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxamci_stop_clock(host); 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->base + MMC_I_MASK); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8179a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu DRCMR(host->dma_drcmrrx) = 0; 8189a788c6b78802b4a378be3f0d4c2da30da811620Bridge Wu DRCMR(host->dma_drcmrtx) = 0; 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(host->irq, host); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_free_dma(host->dma); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(host->base); 8233ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 825ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King clk_put(host->clk); 826ebebd9b0a1463d5de89017ad59a6b9cd4044687fRussell King 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_resource(host->res); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_free_host(mmc); 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 83533264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoportstatic int pxamci_suspend(struct device *dev) 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 83733264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport struct mmc_host *mmc = dev_get_drvdata(dev); 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8409480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King if (mmc) 8411a13f8fa76c880be41d6b1e6a2b44404bcbfdf9eMatt Fleming ret = mmc_suspend_host(mmc); 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84633264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoportstatic int pxamci_resume(struct device *dev) 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 84833264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport struct mmc_host *mmc = dev_get_drvdata(dev); 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8519480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King if (mmc) 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = mmc_resume_host(mmc); 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 85633264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport 857471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops pxamci_pm_ops = { 85833264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport .suspend = pxamci_suspend, 85933264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport .resume = pxamci_resume, 86033264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport}; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8633ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver pxamci_driver = { 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = pxamci_probe, 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = pxamci_remove, 8663ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 8673ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = DRIVER_NAME, 868bc65c724d5a2c61539b2c52680941505152fcf30Kay Sievers .owner = THIS_MODULE, 86933264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport#ifdef CONFIG_PM 87033264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport .pm = &pxamci_pm_ops, 87133264f974526ea8eaaafaa5b87f89abe5a72d472Mike Rapoport#endif 8723ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 875d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(pxamci_driver); 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 879bc65c724d5a2c61539b2c52680941505152fcf30Kay SieversMODULE_ALIAS("platform:pxa2xx-mci"); 880