xref: /openbmc/linux/drivers/mmc/host/sdhci.c (revision 43b58b36)
11c6a0718SPierre Ossman /*
21c6a0718SPierre Ossman  *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
31c6a0718SPierre Ossman  *
41c6a0718SPierre Ossman  *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
51c6a0718SPierre Ossman  *
61c6a0718SPierre Ossman  * This program is free software; you can redistribute it and/or modify
71c6a0718SPierre Ossman  * it under the terms of the GNU General Public License as published by
81c6a0718SPierre Ossman  * the Free Software Foundation; either version 2 of the License, or (at
91c6a0718SPierre Ossman  * your option) any later version.
101c6a0718SPierre Ossman  */
111c6a0718SPierre Ossman 
121c6a0718SPierre Ossman #include <linux/delay.h>
131c6a0718SPierre Ossman #include <linux/highmem.h>
141c6a0718SPierre Ossman #include <linux/pci.h>
151c6a0718SPierre Ossman #include <linux/dma-mapping.h>
161c6a0718SPierre Ossman 
171c6a0718SPierre Ossman #include <linux/mmc/host.h>
181c6a0718SPierre Ossman 
191c6a0718SPierre Ossman #include <asm/scatterlist.h>
201c6a0718SPierre Ossman 
211c6a0718SPierre Ossman #include "sdhci.h"
221c6a0718SPierre Ossman 
231c6a0718SPierre Ossman #define DRIVER_NAME "sdhci"
241c6a0718SPierre Ossman 
251c6a0718SPierre Ossman #define DBG(f, x...) \
261c6a0718SPierre Ossman 	pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
271c6a0718SPierre Ossman 
281c6a0718SPierre Ossman static unsigned int debug_nodma = 0;
291c6a0718SPierre Ossman static unsigned int debug_forcedma = 0;
301c6a0718SPierre Ossman static unsigned int debug_quirks = 0;
311c6a0718SPierre Ossman 
321c6a0718SPierre Ossman #define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
331c6a0718SPierre Ossman #define SDHCI_QUIRK_FORCE_DMA				(1<<1)
341c6a0718SPierre Ossman /* Controller doesn't like some resets when there is no card inserted. */
351c6a0718SPierre Ossman #define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
361c6a0718SPierre Ossman #define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
371c6a0718SPierre Ossman 
381c6a0718SPierre Ossman static const struct pci_device_id pci_ids[] __devinitdata = {
391c6a0718SPierre Ossman 	{
401c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_RICOH,
411c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_RICOH_R5C822,
421c6a0718SPierre Ossman 		.subvendor	= PCI_VENDOR_ID_IBM,
431c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
441c6a0718SPierre Ossman 		.driver_data	= SDHCI_QUIRK_CLOCK_BEFORE_RESET |
451c6a0718SPierre Ossman 				  SDHCI_QUIRK_FORCE_DMA,
461c6a0718SPierre Ossman 	},
471c6a0718SPierre Ossman 
481c6a0718SPierre Ossman 	{
491c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_RICOH,
501c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_RICOH_R5C822,
511c6a0718SPierre Ossman 		.subvendor	= PCI_ANY_ID,
521c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
531c6a0718SPierre Ossman 		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
541c6a0718SPierre Ossman 				  SDHCI_QUIRK_NO_CARD_NO_RESET,
551c6a0718SPierre Ossman 	},
561c6a0718SPierre Ossman 
571c6a0718SPierre Ossman 	{
581c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_TI,
591c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_TI_XX21_XX11_SD,
601c6a0718SPierre Ossman 		.subvendor	= PCI_ANY_ID,
611c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
621c6a0718SPierre Ossman 		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
631c6a0718SPierre Ossman 	},
641c6a0718SPierre Ossman 
651c6a0718SPierre Ossman 	{
661c6a0718SPierre Ossman 		.vendor		= PCI_VENDOR_ID_ENE,
671c6a0718SPierre Ossman 		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
681c6a0718SPierre Ossman 		.subvendor	= PCI_ANY_ID,
691c6a0718SPierre Ossman 		.subdevice	= PCI_ANY_ID,
701c6a0718SPierre Ossman 		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE,
711c6a0718SPierre Ossman 	},
721c6a0718SPierre Ossman 
737de064ebSMilko Krachounov 	{
747de064ebSMilko Krachounov 		.vendor		= PCI_VENDOR_ID_ENE,
757de064ebSMilko Krachounov 		.device		= PCI_DEVICE_ID_ENE_CB712_SD_2,
767de064ebSMilko Krachounov 		.subvendor	= PCI_ANY_ID,
777de064ebSMilko Krachounov 		.subdevice	= PCI_ANY_ID,
787de064ebSMilko Krachounov 		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE,
797de064ebSMilko Krachounov 	},
807de064ebSMilko Krachounov 
811c6a0718SPierre Ossman 	{	/* Generic SD host controller */
821c6a0718SPierre Ossman 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
831c6a0718SPierre Ossman 	},
841c6a0718SPierre Ossman 
851c6a0718SPierre Ossman 	{ /* end: all zeroes */ },
861c6a0718SPierre Ossman };
871c6a0718SPierre Ossman 
881c6a0718SPierre Ossman MODULE_DEVICE_TABLE(pci, pci_ids);
891c6a0718SPierre Ossman 
901c6a0718SPierre Ossman static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
911c6a0718SPierre Ossman static void sdhci_finish_data(struct sdhci_host *);
921c6a0718SPierre Ossman 
931c6a0718SPierre Ossman static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
941c6a0718SPierre Ossman static void sdhci_finish_command(struct sdhci_host *);
951c6a0718SPierre Ossman 
961c6a0718SPierre Ossman static void sdhci_dumpregs(struct sdhci_host *host)
971c6a0718SPierre Ossman {
981c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
991c6a0718SPierre Ossman 
1001c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
1011c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_DMA_ADDRESS),
1021c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_HOST_VERSION));
1031c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
1041c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_BLOCK_SIZE),
1051c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_BLOCK_COUNT));
1061c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
1071c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_ARGUMENT),
1081c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_TRANSFER_MODE));
1091c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
1101c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_PRESENT_STATE),
1111c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_HOST_CONTROL));
1121c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
1131c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_POWER_CONTROL),
1141c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
1151c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
1161c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
1171c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
1181c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
1191c6a0718SPierre Ossman 		readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
1201c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_INT_STATUS));
1211c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
1221c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_INT_ENABLE),
1231c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
1241c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
1251c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_ACMD12_ERR),
1261c6a0718SPierre Ossman 		readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
1271c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
1281c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_CAPABILITIES),
1291c6a0718SPierre Ossman 		readl(host->ioaddr + SDHCI_MAX_CURRENT));
1301c6a0718SPierre Ossman 
1311c6a0718SPierre Ossman 	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
1321c6a0718SPierre Ossman }
1331c6a0718SPierre Ossman 
1341c6a0718SPierre Ossman /*****************************************************************************\
1351c6a0718SPierre Ossman  *                                                                           *
1361c6a0718SPierre Ossman  * Low level functions                                                       *
1371c6a0718SPierre Ossman  *                                                                           *
1381c6a0718SPierre Ossman \*****************************************************************************/
1391c6a0718SPierre Ossman 
1401c6a0718SPierre Ossman static void sdhci_reset(struct sdhci_host *host, u8 mask)
1411c6a0718SPierre Ossman {
1421c6a0718SPierre Ossman 	unsigned long timeout;
1431c6a0718SPierre Ossman 
1441c6a0718SPierre Ossman 	if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
1451c6a0718SPierre Ossman 		if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
1461c6a0718SPierre Ossman 			SDHCI_CARD_PRESENT))
1471c6a0718SPierre Ossman 			return;
1481c6a0718SPierre Ossman 	}
1491c6a0718SPierre Ossman 
1501c6a0718SPierre Ossman 	writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
1511c6a0718SPierre Ossman 
1521c6a0718SPierre Ossman 	if (mask & SDHCI_RESET_ALL)
1531c6a0718SPierre Ossman 		host->clock = 0;
1541c6a0718SPierre Ossman 
1551c6a0718SPierre Ossman 	/* Wait max 100 ms */
1561c6a0718SPierre Ossman 	timeout = 100;
1571c6a0718SPierre Ossman 
1581c6a0718SPierre Ossman 	/* hw clears the bit when it's done */
1591c6a0718SPierre Ossman 	while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
1601c6a0718SPierre Ossman 		if (timeout == 0) {
1611c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
1621c6a0718SPierre Ossman 				mmc_hostname(host->mmc), (int)mask);
1631c6a0718SPierre Ossman 			sdhci_dumpregs(host);
1641c6a0718SPierre Ossman 			return;
1651c6a0718SPierre Ossman 		}
1661c6a0718SPierre Ossman 		timeout--;
1671c6a0718SPierre Ossman 		mdelay(1);
1681c6a0718SPierre Ossman 	}
1691c6a0718SPierre Ossman }
1701c6a0718SPierre Ossman 
1711c6a0718SPierre Ossman static void sdhci_init(struct sdhci_host *host)
1721c6a0718SPierre Ossman {
1731c6a0718SPierre Ossman 	u32 intmask;
1741c6a0718SPierre Ossman 
1751c6a0718SPierre Ossman 	sdhci_reset(host, SDHCI_RESET_ALL);
1761c6a0718SPierre Ossman 
1771c6a0718SPierre Ossman 	intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
1781c6a0718SPierre Ossman 		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
1791c6a0718SPierre Ossman 		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
1801c6a0718SPierre Ossman 		SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
1811c6a0718SPierre Ossman 		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
1821c6a0718SPierre Ossman 		SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
1831c6a0718SPierre Ossman 
1841c6a0718SPierre Ossman 	writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
1851c6a0718SPierre Ossman 	writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
1861c6a0718SPierre Ossman }
1871c6a0718SPierre Ossman 
1881c6a0718SPierre Ossman static void sdhci_activate_led(struct sdhci_host *host)
1891c6a0718SPierre Ossman {
1901c6a0718SPierre Ossman 	u8 ctrl;
1911c6a0718SPierre Ossman 
1921c6a0718SPierre Ossman 	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
1931c6a0718SPierre Ossman 	ctrl |= SDHCI_CTRL_LED;
1941c6a0718SPierre Ossman 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
1951c6a0718SPierre Ossman }
1961c6a0718SPierre Ossman 
1971c6a0718SPierre Ossman static void sdhci_deactivate_led(struct sdhci_host *host)
1981c6a0718SPierre Ossman {
1991c6a0718SPierre Ossman 	u8 ctrl;
2001c6a0718SPierre Ossman 
2011c6a0718SPierre Ossman 	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
2021c6a0718SPierre Ossman 	ctrl &= ~SDHCI_CTRL_LED;
2031c6a0718SPierre Ossman 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
2041c6a0718SPierre Ossman }
2051c6a0718SPierre Ossman 
2061c6a0718SPierre Ossman /*****************************************************************************\
2071c6a0718SPierre Ossman  *                                                                           *
2081c6a0718SPierre Ossman  * Core functions                                                            *
2091c6a0718SPierre Ossman  *                                                                           *
2101c6a0718SPierre Ossman \*****************************************************************************/
2111c6a0718SPierre Ossman 
2121c6a0718SPierre Ossman static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
2131c6a0718SPierre Ossman {
2141c6a0718SPierre Ossman 	return page_address(host->cur_sg->page) + host->cur_sg->offset;
2151c6a0718SPierre Ossman }
2161c6a0718SPierre Ossman 
2171c6a0718SPierre Ossman static inline int sdhci_next_sg(struct sdhci_host* host)
2181c6a0718SPierre Ossman {
2191c6a0718SPierre Ossman 	/*
2201c6a0718SPierre Ossman 	 * Skip to next SG entry.
2211c6a0718SPierre Ossman 	 */
2221c6a0718SPierre Ossman 	host->cur_sg++;
2231c6a0718SPierre Ossman 	host->num_sg--;
2241c6a0718SPierre Ossman 
2251c6a0718SPierre Ossman 	/*
2261c6a0718SPierre Ossman 	 * Any entries left?
2271c6a0718SPierre Ossman 	 */
2281c6a0718SPierre Ossman 	if (host->num_sg > 0) {
2291c6a0718SPierre Ossman 		host->offset = 0;
2301c6a0718SPierre Ossman 		host->remain = host->cur_sg->length;
2311c6a0718SPierre Ossman 	}
2321c6a0718SPierre Ossman 
2331c6a0718SPierre Ossman 	return host->num_sg;
2341c6a0718SPierre Ossman }
2351c6a0718SPierre Ossman 
2361c6a0718SPierre Ossman static void sdhci_read_block_pio(struct sdhci_host *host)
2371c6a0718SPierre Ossman {
2381c6a0718SPierre Ossman 	int blksize, chunk_remain;
2391c6a0718SPierre Ossman 	u32 data;
2401c6a0718SPierre Ossman 	char *buffer;
2411c6a0718SPierre Ossman 	int size;
2421c6a0718SPierre Ossman 
2431c6a0718SPierre Ossman 	DBG("PIO reading\n");
2441c6a0718SPierre Ossman 
2451c6a0718SPierre Ossman 	blksize = host->data->blksz;
2461c6a0718SPierre Ossman 	chunk_remain = 0;
2471c6a0718SPierre Ossman 	data = 0;
2481c6a0718SPierre Ossman 
2491c6a0718SPierre Ossman 	buffer = sdhci_sg_to_buffer(host) + host->offset;
2501c6a0718SPierre Ossman 
2511c6a0718SPierre Ossman 	while (blksize) {
2521c6a0718SPierre Ossman 		if (chunk_remain == 0) {
2531c6a0718SPierre Ossman 			data = readl(host->ioaddr + SDHCI_BUFFER);
2541c6a0718SPierre Ossman 			chunk_remain = min(blksize, 4);
2551c6a0718SPierre Ossman 		}
2561c6a0718SPierre Ossman 
2571c6a0718SPierre Ossman 		size = min(host->remain, chunk_remain);
2581c6a0718SPierre Ossman 
2591c6a0718SPierre Ossman 		chunk_remain -= size;
2601c6a0718SPierre Ossman 		blksize -= size;
2611c6a0718SPierre Ossman 		host->offset += size;
2621c6a0718SPierre Ossman 		host->remain -= size;
2631c6a0718SPierre Ossman 
2641c6a0718SPierre Ossman 		while (size) {
2651c6a0718SPierre Ossman 			*buffer = data & 0xFF;
2661c6a0718SPierre Ossman 			buffer++;
2671c6a0718SPierre Ossman 			data >>= 8;
2681c6a0718SPierre Ossman 			size--;
2691c6a0718SPierre Ossman 		}
2701c6a0718SPierre Ossman 
2711c6a0718SPierre Ossman 		if (host->remain == 0) {
2721c6a0718SPierre Ossman 			if (sdhci_next_sg(host) == 0) {
2731c6a0718SPierre Ossman 				BUG_ON(blksize != 0);
2741c6a0718SPierre Ossman 				return;
2751c6a0718SPierre Ossman 			}
2761c6a0718SPierre Ossman 			buffer = sdhci_sg_to_buffer(host);
2771c6a0718SPierre Ossman 		}
2781c6a0718SPierre Ossman 	}
2791c6a0718SPierre Ossman }
2801c6a0718SPierre Ossman 
2811c6a0718SPierre Ossman static void sdhci_write_block_pio(struct sdhci_host *host)
2821c6a0718SPierre Ossman {
2831c6a0718SPierre Ossman 	int blksize, chunk_remain;
2841c6a0718SPierre Ossman 	u32 data;
2851c6a0718SPierre Ossman 	char *buffer;
2861c6a0718SPierre Ossman 	int bytes, size;
2871c6a0718SPierre Ossman 
2881c6a0718SPierre Ossman 	DBG("PIO writing\n");
2891c6a0718SPierre Ossman 
2901c6a0718SPierre Ossman 	blksize = host->data->blksz;
2911c6a0718SPierre Ossman 	chunk_remain = 4;
2921c6a0718SPierre Ossman 	data = 0;
2931c6a0718SPierre Ossman 
2941c6a0718SPierre Ossman 	bytes = 0;
2951c6a0718SPierre Ossman 	buffer = sdhci_sg_to_buffer(host) + host->offset;
2961c6a0718SPierre Ossman 
2971c6a0718SPierre Ossman 	while (blksize) {
2981c6a0718SPierre Ossman 		size = min(host->remain, chunk_remain);
2991c6a0718SPierre Ossman 
3001c6a0718SPierre Ossman 		chunk_remain -= size;
3011c6a0718SPierre Ossman 		blksize -= size;
3021c6a0718SPierre Ossman 		host->offset += size;
3031c6a0718SPierre Ossman 		host->remain -= size;
3041c6a0718SPierre Ossman 
3051c6a0718SPierre Ossman 		while (size) {
3061c6a0718SPierre Ossman 			data >>= 8;
3071c6a0718SPierre Ossman 			data |= (u32)*buffer << 24;
3081c6a0718SPierre Ossman 			buffer++;
3091c6a0718SPierre Ossman 			size--;
3101c6a0718SPierre Ossman 		}
3111c6a0718SPierre Ossman 
3121c6a0718SPierre Ossman 		if (chunk_remain == 0) {
3131c6a0718SPierre Ossman 			writel(data, host->ioaddr + SDHCI_BUFFER);
3141c6a0718SPierre Ossman 			chunk_remain = min(blksize, 4);
3151c6a0718SPierre Ossman 		}
3161c6a0718SPierre Ossman 
3171c6a0718SPierre Ossman 		if (host->remain == 0) {
3181c6a0718SPierre Ossman 			if (sdhci_next_sg(host) == 0) {
3191c6a0718SPierre Ossman 				BUG_ON(blksize != 0);
3201c6a0718SPierre Ossman 				return;
3211c6a0718SPierre Ossman 			}
3221c6a0718SPierre Ossman 			buffer = sdhci_sg_to_buffer(host);
3231c6a0718SPierre Ossman 		}
3241c6a0718SPierre Ossman 	}
3251c6a0718SPierre Ossman }
3261c6a0718SPierre Ossman 
3271c6a0718SPierre Ossman static void sdhci_transfer_pio(struct sdhci_host *host)
3281c6a0718SPierre Ossman {
3291c6a0718SPierre Ossman 	u32 mask;
3301c6a0718SPierre Ossman 
3311c6a0718SPierre Ossman 	BUG_ON(!host->data);
3321c6a0718SPierre Ossman 
3331c6a0718SPierre Ossman 	if (host->num_sg == 0)
3341c6a0718SPierre Ossman 		return;
3351c6a0718SPierre Ossman 
3361c6a0718SPierre Ossman 	if (host->data->flags & MMC_DATA_READ)
3371c6a0718SPierre Ossman 		mask = SDHCI_DATA_AVAILABLE;
3381c6a0718SPierre Ossman 	else
3391c6a0718SPierre Ossman 		mask = SDHCI_SPACE_AVAILABLE;
3401c6a0718SPierre Ossman 
3411c6a0718SPierre Ossman 	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
3421c6a0718SPierre Ossman 		if (host->data->flags & MMC_DATA_READ)
3431c6a0718SPierre Ossman 			sdhci_read_block_pio(host);
3441c6a0718SPierre Ossman 		else
3451c6a0718SPierre Ossman 			sdhci_write_block_pio(host);
3461c6a0718SPierre Ossman 
3471c6a0718SPierre Ossman 		if (host->num_sg == 0)
3481c6a0718SPierre Ossman 			break;
3491c6a0718SPierre Ossman 	}
3501c6a0718SPierre Ossman 
3511c6a0718SPierre Ossman 	DBG("PIO transfer complete.\n");
3521c6a0718SPierre Ossman }
3531c6a0718SPierre Ossman 
3541c6a0718SPierre Ossman static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
3551c6a0718SPierre Ossman {
3561c6a0718SPierre Ossman 	u8 count;
3571c6a0718SPierre Ossman 	unsigned target_timeout, current_timeout;
3581c6a0718SPierre Ossman 
3591c6a0718SPierre Ossman 	WARN_ON(host->data);
3601c6a0718SPierre Ossman 
3611c6a0718SPierre Ossman 	if (data == NULL)
3621c6a0718SPierre Ossman 		return;
3631c6a0718SPierre Ossman 
3641c6a0718SPierre Ossman 	DBG("blksz %04x blks %04x flags %08x\n",
3651c6a0718SPierre Ossman 		data->blksz, data->blocks, data->flags);
3661c6a0718SPierre Ossman 	DBG("tsac %d ms nsac %d clk\n",
3671c6a0718SPierre Ossman 		data->timeout_ns / 1000000, data->timeout_clks);
3681c6a0718SPierre Ossman 
3691c6a0718SPierre Ossman 	/* Sanity checks */
3701c6a0718SPierre Ossman 	BUG_ON(data->blksz * data->blocks > 524288);
3711c6a0718SPierre Ossman 	BUG_ON(data->blksz > host->mmc->max_blk_size);
3721c6a0718SPierre Ossman 	BUG_ON(data->blocks > 65535);
3731c6a0718SPierre Ossman 
3741c6a0718SPierre Ossman 	/* timeout in us */
3751c6a0718SPierre Ossman 	target_timeout = data->timeout_ns / 1000 +
3761c6a0718SPierre Ossman 		data->timeout_clks / host->clock;
3771c6a0718SPierre Ossman 
3781c6a0718SPierre Ossman 	/*
3791c6a0718SPierre Ossman 	 * Figure out needed cycles.
3801c6a0718SPierre Ossman 	 * We do this in steps in order to fit inside a 32 bit int.
3811c6a0718SPierre Ossman 	 * The first step is the minimum timeout, which will have a
3821c6a0718SPierre Ossman 	 * minimum resolution of 6 bits:
3831c6a0718SPierre Ossman 	 * (1) 2^13*1000 > 2^22,
3841c6a0718SPierre Ossman 	 * (2) host->timeout_clk < 2^16
3851c6a0718SPierre Ossman 	 *     =>
3861c6a0718SPierre Ossman 	 *     (1) / (2) > 2^6
3871c6a0718SPierre Ossman 	 */
3881c6a0718SPierre Ossman 	count = 0;
3891c6a0718SPierre Ossman 	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
3901c6a0718SPierre Ossman 	while (current_timeout < target_timeout) {
3911c6a0718SPierre Ossman 		count++;
3921c6a0718SPierre Ossman 		current_timeout <<= 1;
3931c6a0718SPierre Ossman 		if (count >= 0xF)
3941c6a0718SPierre Ossman 			break;
3951c6a0718SPierre Ossman 	}
3961c6a0718SPierre Ossman 
3971c6a0718SPierre Ossman 	if (count >= 0xF) {
3981c6a0718SPierre Ossman 		printk(KERN_WARNING "%s: Too large timeout requested!\n",
3991c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
4001c6a0718SPierre Ossman 		count = 0xE;
4011c6a0718SPierre Ossman 	}
4021c6a0718SPierre Ossman 
4031c6a0718SPierre Ossman 	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
4041c6a0718SPierre Ossman 
4051c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA) {
4061c6a0718SPierre Ossman 		int count;
4071c6a0718SPierre Ossman 
4081c6a0718SPierre Ossman 		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
4091c6a0718SPierre Ossman 			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
4101c6a0718SPierre Ossman 		BUG_ON(count != 1);
4111c6a0718SPierre Ossman 
4121c6a0718SPierre Ossman 		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
4131c6a0718SPierre Ossman 	} else {
4141c6a0718SPierre Ossman 		host->cur_sg = data->sg;
4151c6a0718SPierre Ossman 		host->num_sg = data->sg_len;
4161c6a0718SPierre Ossman 
4171c6a0718SPierre Ossman 		host->offset = 0;
4181c6a0718SPierre Ossman 		host->remain = host->cur_sg->length;
4191c6a0718SPierre Ossman 	}
4201c6a0718SPierre Ossman 
4211c6a0718SPierre Ossman 	/* We do not handle DMA boundaries, so set it to max (512 KiB) */
4221c6a0718SPierre Ossman 	writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
4231c6a0718SPierre Ossman 		host->ioaddr + SDHCI_BLOCK_SIZE);
4241c6a0718SPierre Ossman 	writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
4251c6a0718SPierre Ossman }
4261c6a0718SPierre Ossman 
4271c6a0718SPierre Ossman static void sdhci_set_transfer_mode(struct sdhci_host *host,
4281c6a0718SPierre Ossman 	struct mmc_data *data)
4291c6a0718SPierre Ossman {
4301c6a0718SPierre Ossman 	u16 mode;
4311c6a0718SPierre Ossman 
4321c6a0718SPierre Ossman 	WARN_ON(host->data);
4331c6a0718SPierre Ossman 
4341c6a0718SPierre Ossman 	if (data == NULL)
4351c6a0718SPierre Ossman 		return;
4361c6a0718SPierre Ossman 
4371c6a0718SPierre Ossman 	mode = SDHCI_TRNS_BLK_CNT_EN;
4381c6a0718SPierre Ossman 	if (data->blocks > 1)
4391c6a0718SPierre Ossman 		mode |= SDHCI_TRNS_MULTI;
4401c6a0718SPierre Ossman 	if (data->flags & MMC_DATA_READ)
4411c6a0718SPierre Ossman 		mode |= SDHCI_TRNS_READ;
4421c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA)
4431c6a0718SPierre Ossman 		mode |= SDHCI_TRNS_DMA;
4441c6a0718SPierre Ossman 
4451c6a0718SPierre Ossman 	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
4461c6a0718SPierre Ossman }
4471c6a0718SPierre Ossman 
4481c6a0718SPierre Ossman static void sdhci_finish_data(struct sdhci_host *host)
4491c6a0718SPierre Ossman {
4501c6a0718SPierre Ossman 	struct mmc_data *data;
4511c6a0718SPierre Ossman 	u16 blocks;
4521c6a0718SPierre Ossman 
4531c6a0718SPierre Ossman 	BUG_ON(!host->data);
4541c6a0718SPierre Ossman 
4551c6a0718SPierre Ossman 	data = host->data;
4561c6a0718SPierre Ossman 	host->data = NULL;
4571c6a0718SPierre Ossman 
4581c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA) {
4591c6a0718SPierre Ossman 		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
4601c6a0718SPierre Ossman 			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
4611c6a0718SPierre Ossman 	}
4621c6a0718SPierre Ossman 
4631c6a0718SPierre Ossman 	/*
4641c6a0718SPierre Ossman 	 * Controller doesn't count down when in single block mode.
4651c6a0718SPierre Ossman 	 */
4661c6a0718SPierre Ossman 	if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
4671c6a0718SPierre Ossman 		blocks = 0;
4681c6a0718SPierre Ossman 	else
4691c6a0718SPierre Ossman 		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
4701c6a0718SPierre Ossman 	data->bytes_xfered = data->blksz * (data->blocks - blocks);
4711c6a0718SPierre Ossman 
4721c6a0718SPierre Ossman 	if ((data->error == MMC_ERR_NONE) && blocks) {
4731c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Controller signalled completion even "
4741c6a0718SPierre Ossman 			"though there were blocks left.\n",
4751c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
4761c6a0718SPierre Ossman 		data->error = MMC_ERR_FAILED;
4771c6a0718SPierre Ossman 	}
4781c6a0718SPierre Ossman 
4791c6a0718SPierre Ossman 	DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
4801c6a0718SPierre Ossman 
4811c6a0718SPierre Ossman 	if (data->stop) {
4821c6a0718SPierre Ossman 		/*
4831c6a0718SPierre Ossman 		 * The controller needs a reset of internal state machines
4841c6a0718SPierre Ossman 		 * upon error conditions.
4851c6a0718SPierre Ossman 		 */
4861c6a0718SPierre Ossman 		if (data->error != MMC_ERR_NONE) {
4871c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_CMD);
4881c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_DATA);
4891c6a0718SPierre Ossman 		}
4901c6a0718SPierre Ossman 
4911c6a0718SPierre Ossman 		sdhci_send_command(host, data->stop);
4921c6a0718SPierre Ossman 	} else
4931c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
4941c6a0718SPierre Ossman }
4951c6a0718SPierre Ossman 
4961c6a0718SPierre Ossman static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
4971c6a0718SPierre Ossman {
4981c6a0718SPierre Ossman 	int flags;
4991c6a0718SPierre Ossman 	u32 mask;
5001c6a0718SPierre Ossman 	unsigned long timeout;
5011c6a0718SPierre Ossman 
5021c6a0718SPierre Ossman 	WARN_ON(host->cmd);
5031c6a0718SPierre Ossman 
5041c6a0718SPierre Ossman 	DBG("Sending cmd (%x)\n", cmd->opcode);
5051c6a0718SPierre Ossman 
5061c6a0718SPierre Ossman 	/* Wait max 10 ms */
5071c6a0718SPierre Ossman 	timeout = 10;
5081c6a0718SPierre Ossman 
5091c6a0718SPierre Ossman 	mask = SDHCI_CMD_INHIBIT;
5101c6a0718SPierre Ossman 	if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
5111c6a0718SPierre Ossman 		mask |= SDHCI_DATA_INHIBIT;
5121c6a0718SPierre Ossman 
5131c6a0718SPierre Ossman 	/* We shouldn't wait for data inihibit for stop commands, even
5141c6a0718SPierre Ossman 	   though they might use busy signaling */
5151c6a0718SPierre Ossman 	if (host->mrq->data && (cmd == host->mrq->data->stop))
5161c6a0718SPierre Ossman 		mask &= ~SDHCI_DATA_INHIBIT;
5171c6a0718SPierre Ossman 
5181c6a0718SPierre Ossman 	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
5191c6a0718SPierre Ossman 		if (timeout == 0) {
5201c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Controller never released "
5211c6a0718SPierre Ossman 				"inhibit bit(s).\n", mmc_hostname(host->mmc));
5221c6a0718SPierre Ossman 			sdhci_dumpregs(host);
5231c6a0718SPierre Ossman 			cmd->error = MMC_ERR_FAILED;
5241c6a0718SPierre Ossman 			tasklet_schedule(&host->finish_tasklet);
5251c6a0718SPierre Ossman 			return;
5261c6a0718SPierre Ossman 		}
5271c6a0718SPierre Ossman 		timeout--;
5281c6a0718SPierre Ossman 		mdelay(1);
5291c6a0718SPierre Ossman 	}
5301c6a0718SPierre Ossman 
5311c6a0718SPierre Ossman 	mod_timer(&host->timer, jiffies + 10 * HZ);
5321c6a0718SPierre Ossman 
5331c6a0718SPierre Ossman 	host->cmd = cmd;
5341c6a0718SPierre Ossman 
5351c6a0718SPierre Ossman 	sdhci_prepare_data(host, cmd->data);
5361c6a0718SPierre Ossman 
5371c6a0718SPierre Ossman 	writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
5381c6a0718SPierre Ossman 
5391c6a0718SPierre Ossman 	sdhci_set_transfer_mode(host, cmd->data);
5401c6a0718SPierre Ossman 
5411c6a0718SPierre Ossman 	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
5421c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Unsupported response type!\n",
5431c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
5441c6a0718SPierre Ossman 		cmd->error = MMC_ERR_INVALID;
5451c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
5461c6a0718SPierre Ossman 		return;
5471c6a0718SPierre Ossman 	}
5481c6a0718SPierre Ossman 
5491c6a0718SPierre Ossman 	if (!(cmd->flags & MMC_RSP_PRESENT))
5501c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_NONE;
5511c6a0718SPierre Ossman 	else if (cmd->flags & MMC_RSP_136)
5521c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_LONG;
5531c6a0718SPierre Ossman 	else if (cmd->flags & MMC_RSP_BUSY)
5541c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_SHORT_BUSY;
5551c6a0718SPierre Ossman 	else
5561c6a0718SPierre Ossman 		flags = SDHCI_CMD_RESP_SHORT;
5571c6a0718SPierre Ossman 
5581c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_CRC)
5591c6a0718SPierre Ossman 		flags |= SDHCI_CMD_CRC;
5601c6a0718SPierre Ossman 	if (cmd->flags & MMC_RSP_OPCODE)
5611c6a0718SPierre Ossman 		flags |= SDHCI_CMD_INDEX;
5621c6a0718SPierre Ossman 	if (cmd->data)
5631c6a0718SPierre Ossman 		flags |= SDHCI_CMD_DATA;
5641c6a0718SPierre Ossman 
5651c6a0718SPierre Ossman 	writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
5661c6a0718SPierre Ossman 		host->ioaddr + SDHCI_COMMAND);
5671c6a0718SPierre Ossman }
5681c6a0718SPierre Ossman 
5691c6a0718SPierre Ossman static void sdhci_finish_command(struct sdhci_host *host)
5701c6a0718SPierre Ossman {
5711c6a0718SPierre Ossman 	int i;
5721c6a0718SPierre Ossman 
5731c6a0718SPierre Ossman 	BUG_ON(host->cmd == NULL);
5741c6a0718SPierre Ossman 
5751c6a0718SPierre Ossman 	if (host->cmd->flags & MMC_RSP_PRESENT) {
5761c6a0718SPierre Ossman 		if (host->cmd->flags & MMC_RSP_136) {
5771c6a0718SPierre Ossman 			/* CRC is stripped so we need to do some shifting. */
5781c6a0718SPierre Ossman 			for (i = 0;i < 4;i++) {
5791c6a0718SPierre Ossman 				host->cmd->resp[i] = readl(host->ioaddr +
5801c6a0718SPierre Ossman 					SDHCI_RESPONSE + (3-i)*4) << 8;
5811c6a0718SPierre Ossman 				if (i != 3)
5821c6a0718SPierre Ossman 					host->cmd->resp[i] |=
5831c6a0718SPierre Ossman 						readb(host->ioaddr +
5841c6a0718SPierre Ossman 						SDHCI_RESPONSE + (3-i)*4-1);
5851c6a0718SPierre Ossman 			}
5861c6a0718SPierre Ossman 		} else {
5871c6a0718SPierre Ossman 			host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
5881c6a0718SPierre Ossman 		}
5891c6a0718SPierre Ossman 	}
5901c6a0718SPierre Ossman 
5911c6a0718SPierre Ossman 	host->cmd->error = MMC_ERR_NONE;
5921c6a0718SPierre Ossman 
5931c6a0718SPierre Ossman 	DBG("Ending cmd (%x)\n", host->cmd->opcode);
5941c6a0718SPierre Ossman 
5951c6a0718SPierre Ossman 	if (host->cmd->data)
5961c6a0718SPierre Ossman 		host->data = host->cmd->data;
5971c6a0718SPierre Ossman 	else
5981c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
5991c6a0718SPierre Ossman 
6001c6a0718SPierre Ossman 	host->cmd = NULL;
6011c6a0718SPierre Ossman }
6021c6a0718SPierre Ossman 
6031c6a0718SPierre Ossman static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
6041c6a0718SPierre Ossman {
6051c6a0718SPierre Ossman 	int div;
6061c6a0718SPierre Ossman 	u16 clk;
6071c6a0718SPierre Ossman 	unsigned long timeout;
6081c6a0718SPierre Ossman 
6091c6a0718SPierre Ossman 	if (clock == host->clock)
6101c6a0718SPierre Ossman 		return;
6111c6a0718SPierre Ossman 
6121c6a0718SPierre Ossman 	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
6131c6a0718SPierre Ossman 
6141c6a0718SPierre Ossman 	if (clock == 0)
6151c6a0718SPierre Ossman 		goto out;
6161c6a0718SPierre Ossman 
6171c6a0718SPierre Ossman 	for (div = 1;div < 256;div *= 2) {
6181c6a0718SPierre Ossman 		if ((host->max_clk / div) <= clock)
6191c6a0718SPierre Ossman 			break;
6201c6a0718SPierre Ossman 	}
6211c6a0718SPierre Ossman 	div >>= 1;
6221c6a0718SPierre Ossman 
6231c6a0718SPierre Ossman 	clk = div << SDHCI_DIVIDER_SHIFT;
6241c6a0718SPierre Ossman 	clk |= SDHCI_CLOCK_INT_EN;
6251c6a0718SPierre Ossman 	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
6261c6a0718SPierre Ossman 
6271c6a0718SPierre Ossman 	/* Wait max 10 ms */
6281c6a0718SPierre Ossman 	timeout = 10;
6291c6a0718SPierre Ossman 	while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
6301c6a0718SPierre Ossman 		& SDHCI_CLOCK_INT_STABLE)) {
6311c6a0718SPierre Ossman 		if (timeout == 0) {
6321c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Internal clock never "
6331c6a0718SPierre Ossman 				"stabilised.\n", mmc_hostname(host->mmc));
6341c6a0718SPierre Ossman 			sdhci_dumpregs(host);
6351c6a0718SPierre Ossman 			return;
6361c6a0718SPierre Ossman 		}
6371c6a0718SPierre Ossman 		timeout--;
6381c6a0718SPierre Ossman 		mdelay(1);
6391c6a0718SPierre Ossman 	}
6401c6a0718SPierre Ossman 
6411c6a0718SPierre Ossman 	clk |= SDHCI_CLOCK_CARD_EN;
6421c6a0718SPierre Ossman 	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
6431c6a0718SPierre Ossman 
6441c6a0718SPierre Ossman out:
6451c6a0718SPierre Ossman 	host->clock = clock;
6461c6a0718SPierre Ossman }
6471c6a0718SPierre Ossman 
6481c6a0718SPierre Ossman static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
6491c6a0718SPierre Ossman {
6501c6a0718SPierre Ossman 	u8 pwr;
6511c6a0718SPierre Ossman 
6521c6a0718SPierre Ossman 	if (host->power == power)
6531c6a0718SPierre Ossman 		return;
6541c6a0718SPierre Ossman 
6551c6a0718SPierre Ossman 	if (power == (unsigned short)-1) {
6561c6a0718SPierre Ossman 		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
6571c6a0718SPierre Ossman 		goto out;
6581c6a0718SPierre Ossman 	}
6591c6a0718SPierre Ossman 
6601c6a0718SPierre Ossman 	/*
6611c6a0718SPierre Ossman 	 * Spec says that we should clear the power reg before setting
6621c6a0718SPierre Ossman 	 * a new value. Some controllers don't seem to like this though.
6631c6a0718SPierre Ossman 	 */
6641c6a0718SPierre Ossman 	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
6651c6a0718SPierre Ossman 		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
6661c6a0718SPierre Ossman 
6671c6a0718SPierre Ossman 	pwr = SDHCI_POWER_ON;
6681c6a0718SPierre Ossman 
6694be34c99SPhilip Langdale 	switch (1 << power) {
67055556da0SPhilip Langdale 	case MMC_VDD_165_195:
6711c6a0718SPierre Ossman 		pwr |= SDHCI_POWER_180;
6721c6a0718SPierre Ossman 		break;
6734be34c99SPhilip Langdale 	case MMC_VDD_29_30:
6744be34c99SPhilip Langdale 	case MMC_VDD_30_31:
6751c6a0718SPierre Ossman 		pwr |= SDHCI_POWER_300;
6761c6a0718SPierre Ossman 		break;
6774be34c99SPhilip Langdale 	case MMC_VDD_32_33:
6784be34c99SPhilip Langdale 	case MMC_VDD_33_34:
6791c6a0718SPierre Ossman 		pwr |= SDHCI_POWER_330;
6801c6a0718SPierre Ossman 		break;
6811c6a0718SPierre Ossman 	default:
6821c6a0718SPierre Ossman 		BUG();
6831c6a0718SPierre Ossman 	}
6841c6a0718SPierre Ossman 
6851c6a0718SPierre Ossman 	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
6861c6a0718SPierre Ossman 
6871c6a0718SPierre Ossman out:
6881c6a0718SPierre Ossman 	host->power = power;
6891c6a0718SPierre Ossman }
6901c6a0718SPierre Ossman 
6911c6a0718SPierre Ossman /*****************************************************************************\
6921c6a0718SPierre Ossman  *                                                                           *
6931c6a0718SPierre Ossman  * MMC callbacks                                                             *
6941c6a0718SPierre Ossman  *                                                                           *
6951c6a0718SPierre Ossman \*****************************************************************************/
6961c6a0718SPierre Ossman 
6971c6a0718SPierre Ossman static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
6981c6a0718SPierre Ossman {
6991c6a0718SPierre Ossman 	struct sdhci_host *host;
7001c6a0718SPierre Ossman 	unsigned long flags;
7011c6a0718SPierre Ossman 
7021c6a0718SPierre Ossman 	host = mmc_priv(mmc);
7031c6a0718SPierre Ossman 
7041c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
7051c6a0718SPierre Ossman 
7061c6a0718SPierre Ossman 	WARN_ON(host->mrq != NULL);
7071c6a0718SPierre Ossman 
7081c6a0718SPierre Ossman 	sdhci_activate_led(host);
7091c6a0718SPierre Ossman 
7101c6a0718SPierre Ossman 	host->mrq = mrq;
7111c6a0718SPierre Ossman 
7121c6a0718SPierre Ossman 	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
7131c6a0718SPierre Ossman 		host->mrq->cmd->error = MMC_ERR_TIMEOUT;
7141c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
7151c6a0718SPierre Ossman 	} else
7161c6a0718SPierre Ossman 		sdhci_send_command(host, mrq->cmd);
7171c6a0718SPierre Ossman 
7181c6a0718SPierre Ossman 	mmiowb();
7191c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
7201c6a0718SPierre Ossman }
7211c6a0718SPierre Ossman 
7221c6a0718SPierre Ossman static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
7231c6a0718SPierre Ossman {
7241c6a0718SPierre Ossman 	struct sdhci_host *host;
7251c6a0718SPierre Ossman 	unsigned long flags;
7261c6a0718SPierre Ossman 	u8 ctrl;
7271c6a0718SPierre Ossman 
7281c6a0718SPierre Ossman 	host = mmc_priv(mmc);
7291c6a0718SPierre Ossman 
7301c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
7311c6a0718SPierre Ossman 
7321c6a0718SPierre Ossman 	/*
7331c6a0718SPierre Ossman 	 * Reset the chip on each power off.
7341c6a0718SPierre Ossman 	 * Should clear out any weird states.
7351c6a0718SPierre Ossman 	 */
7361c6a0718SPierre Ossman 	if (ios->power_mode == MMC_POWER_OFF) {
7371c6a0718SPierre Ossman 		writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
7381c6a0718SPierre Ossman 		sdhci_init(host);
7391c6a0718SPierre Ossman 	}
7401c6a0718SPierre Ossman 
7411c6a0718SPierre Ossman 	sdhci_set_clock(host, ios->clock);
7421c6a0718SPierre Ossman 
7431c6a0718SPierre Ossman 	if (ios->power_mode == MMC_POWER_OFF)
7441c6a0718SPierre Ossman 		sdhci_set_power(host, -1);
7451c6a0718SPierre Ossman 	else
7461c6a0718SPierre Ossman 		sdhci_set_power(host, ios->vdd);
7471c6a0718SPierre Ossman 
7481c6a0718SPierre Ossman 	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
7491c6a0718SPierre Ossman 
7501c6a0718SPierre Ossman 	if (ios->bus_width == MMC_BUS_WIDTH_4)
7511c6a0718SPierre Ossman 		ctrl |= SDHCI_CTRL_4BITBUS;
7521c6a0718SPierre Ossman 	else
7531c6a0718SPierre Ossman 		ctrl &= ~SDHCI_CTRL_4BITBUS;
7541c6a0718SPierre Ossman 
7551c6a0718SPierre Ossman 	if (ios->timing == MMC_TIMING_SD_HS)
7561c6a0718SPierre Ossman 		ctrl |= SDHCI_CTRL_HISPD;
7571c6a0718SPierre Ossman 	else
7581c6a0718SPierre Ossman 		ctrl &= ~SDHCI_CTRL_HISPD;
7591c6a0718SPierre Ossman 
7601c6a0718SPierre Ossman 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
7611c6a0718SPierre Ossman 
7621c6a0718SPierre Ossman 	mmiowb();
7631c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
7641c6a0718SPierre Ossman }
7651c6a0718SPierre Ossman 
7661c6a0718SPierre Ossman static int sdhci_get_ro(struct mmc_host *mmc)
7671c6a0718SPierre Ossman {
7681c6a0718SPierre Ossman 	struct sdhci_host *host;
7691c6a0718SPierre Ossman 	unsigned long flags;
7701c6a0718SPierre Ossman 	int present;
7711c6a0718SPierre Ossman 
7721c6a0718SPierre Ossman 	host = mmc_priv(mmc);
7731c6a0718SPierre Ossman 
7741c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
7751c6a0718SPierre Ossman 
7761c6a0718SPierre Ossman 	present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
7771c6a0718SPierre Ossman 
7781c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
7791c6a0718SPierre Ossman 
7801c6a0718SPierre Ossman 	return !(present & SDHCI_WRITE_PROTECT);
7811c6a0718SPierre Ossman }
7821c6a0718SPierre Ossman 
7831c6a0718SPierre Ossman static const struct mmc_host_ops sdhci_ops = {
7841c6a0718SPierre Ossman 	.request	= sdhci_request,
7851c6a0718SPierre Ossman 	.set_ios	= sdhci_set_ios,
7861c6a0718SPierre Ossman 	.get_ro		= sdhci_get_ro,
7871c6a0718SPierre Ossman };
7881c6a0718SPierre Ossman 
7891c6a0718SPierre Ossman /*****************************************************************************\
7901c6a0718SPierre Ossman  *                                                                           *
7911c6a0718SPierre Ossman  * Tasklets                                                                  *
7921c6a0718SPierre Ossman  *                                                                           *
7931c6a0718SPierre Ossman \*****************************************************************************/
7941c6a0718SPierre Ossman 
7951c6a0718SPierre Ossman static void sdhci_tasklet_card(unsigned long param)
7961c6a0718SPierre Ossman {
7971c6a0718SPierre Ossman 	struct sdhci_host *host;
7981c6a0718SPierre Ossman 	unsigned long flags;
7991c6a0718SPierre Ossman 
8001c6a0718SPierre Ossman 	host = (struct sdhci_host*)param;
8011c6a0718SPierre Ossman 
8021c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
8031c6a0718SPierre Ossman 
8041c6a0718SPierre Ossman 	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
8051c6a0718SPierre Ossman 		if (host->mrq) {
8061c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Card removed during transfer!\n",
8071c6a0718SPierre Ossman 				mmc_hostname(host->mmc));
8081c6a0718SPierre Ossman 			printk(KERN_ERR "%s: Resetting controller.\n",
8091c6a0718SPierre Ossman 				mmc_hostname(host->mmc));
8101c6a0718SPierre Ossman 
8111c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_CMD);
8121c6a0718SPierre Ossman 			sdhci_reset(host, SDHCI_RESET_DATA);
8131c6a0718SPierre Ossman 
8141c6a0718SPierre Ossman 			host->mrq->cmd->error = MMC_ERR_FAILED;
8151c6a0718SPierre Ossman 			tasklet_schedule(&host->finish_tasklet);
8161c6a0718SPierre Ossman 		}
8171c6a0718SPierre Ossman 	}
8181c6a0718SPierre Ossman 
8191c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
8201c6a0718SPierre Ossman 
8211c6a0718SPierre Ossman 	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
8221c6a0718SPierre Ossman }
8231c6a0718SPierre Ossman 
8241c6a0718SPierre Ossman static void sdhci_tasklet_finish(unsigned long param)
8251c6a0718SPierre Ossman {
8261c6a0718SPierre Ossman 	struct sdhci_host *host;
8271c6a0718SPierre Ossman 	unsigned long flags;
8281c6a0718SPierre Ossman 	struct mmc_request *mrq;
8291c6a0718SPierre Ossman 
8301c6a0718SPierre Ossman 	host = (struct sdhci_host*)param;
8311c6a0718SPierre Ossman 
8321c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
8331c6a0718SPierre Ossman 
8341c6a0718SPierre Ossman 	del_timer(&host->timer);
8351c6a0718SPierre Ossman 
8361c6a0718SPierre Ossman 	mrq = host->mrq;
8371c6a0718SPierre Ossman 
8381c6a0718SPierre Ossman 	DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
8391c6a0718SPierre Ossman 
8401c6a0718SPierre Ossman 	/*
8411c6a0718SPierre Ossman 	 * The controller needs a reset of internal state machines
8421c6a0718SPierre Ossman 	 * upon error conditions.
8431c6a0718SPierre Ossman 	 */
8441c6a0718SPierre Ossman 	if ((mrq->cmd->error != MMC_ERR_NONE) ||
8451c6a0718SPierre Ossman 		(mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
8461c6a0718SPierre Ossman 		(mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
8471c6a0718SPierre Ossman 
8481c6a0718SPierre Ossman 		/* Some controllers need this kick or reset won't work here */
8491c6a0718SPierre Ossman 		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
8501c6a0718SPierre Ossman 			unsigned int clock;
8511c6a0718SPierre Ossman 
8521c6a0718SPierre Ossman 			/* This is to force an update */
8531c6a0718SPierre Ossman 			clock = host->clock;
8541c6a0718SPierre Ossman 			host->clock = 0;
8551c6a0718SPierre Ossman 			sdhci_set_clock(host, clock);
8561c6a0718SPierre Ossman 		}
8571c6a0718SPierre Ossman 
8581c6a0718SPierre Ossman 		/* Spec says we should do both at the same time, but Ricoh
8591c6a0718SPierre Ossman 		   controllers do not like that. */
8601c6a0718SPierre Ossman 		sdhci_reset(host, SDHCI_RESET_CMD);
8611c6a0718SPierre Ossman 		sdhci_reset(host, SDHCI_RESET_DATA);
8621c6a0718SPierre Ossman 	}
8631c6a0718SPierre Ossman 
8641c6a0718SPierre Ossman 	host->mrq = NULL;
8651c6a0718SPierre Ossman 	host->cmd = NULL;
8661c6a0718SPierre Ossman 	host->data = NULL;
8671c6a0718SPierre Ossman 
8681c6a0718SPierre Ossman 	sdhci_deactivate_led(host);
8691c6a0718SPierre Ossman 
8701c6a0718SPierre Ossman 	mmiowb();
8711c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
8721c6a0718SPierre Ossman 
8731c6a0718SPierre Ossman 	mmc_request_done(host->mmc, mrq);
8741c6a0718SPierre Ossman }
8751c6a0718SPierre Ossman 
8761c6a0718SPierre Ossman static void sdhci_timeout_timer(unsigned long data)
8771c6a0718SPierre Ossman {
8781c6a0718SPierre Ossman 	struct sdhci_host *host;
8791c6a0718SPierre Ossman 	unsigned long flags;
8801c6a0718SPierre Ossman 
8811c6a0718SPierre Ossman 	host = (struct sdhci_host*)data;
8821c6a0718SPierre Ossman 
8831c6a0718SPierre Ossman 	spin_lock_irqsave(&host->lock, flags);
8841c6a0718SPierre Ossman 
8851c6a0718SPierre Ossman 	if (host->mrq) {
8861c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Timeout waiting for hardware "
8871c6a0718SPierre Ossman 			"interrupt.\n", mmc_hostname(host->mmc));
8881c6a0718SPierre Ossman 		sdhci_dumpregs(host);
8891c6a0718SPierre Ossman 
8901c6a0718SPierre Ossman 		if (host->data) {
8911c6a0718SPierre Ossman 			host->data->error = MMC_ERR_TIMEOUT;
8921c6a0718SPierre Ossman 			sdhci_finish_data(host);
8931c6a0718SPierre Ossman 		} else {
8941c6a0718SPierre Ossman 			if (host->cmd)
8951c6a0718SPierre Ossman 				host->cmd->error = MMC_ERR_TIMEOUT;
8961c6a0718SPierre Ossman 			else
8971c6a0718SPierre Ossman 				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
8981c6a0718SPierre Ossman 
8991c6a0718SPierre Ossman 			tasklet_schedule(&host->finish_tasklet);
9001c6a0718SPierre Ossman 		}
9011c6a0718SPierre Ossman 	}
9021c6a0718SPierre Ossman 
9031c6a0718SPierre Ossman 	mmiowb();
9041c6a0718SPierre Ossman 	spin_unlock_irqrestore(&host->lock, flags);
9051c6a0718SPierre Ossman }
9061c6a0718SPierre Ossman 
9071c6a0718SPierre Ossman /*****************************************************************************\
9081c6a0718SPierre Ossman  *                                                                           *
9091c6a0718SPierre Ossman  * Interrupt handling                                                        *
9101c6a0718SPierre Ossman  *                                                                           *
9111c6a0718SPierre Ossman \*****************************************************************************/
9121c6a0718SPierre Ossman 
9131c6a0718SPierre Ossman static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
9141c6a0718SPierre Ossman {
9151c6a0718SPierre Ossman 	BUG_ON(intmask == 0);
9161c6a0718SPierre Ossman 
9171c6a0718SPierre Ossman 	if (!host->cmd) {
9181c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Got command interrupt even though no "
9191c6a0718SPierre Ossman 			"command operation was in progress.\n",
9201c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
9211c6a0718SPierre Ossman 		sdhci_dumpregs(host);
9221c6a0718SPierre Ossman 		return;
9231c6a0718SPierre Ossman 	}
9241c6a0718SPierre Ossman 
9251c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_TIMEOUT)
9261c6a0718SPierre Ossman 		host->cmd->error = MMC_ERR_TIMEOUT;
9271c6a0718SPierre Ossman 	else if (intmask & SDHCI_INT_CRC)
9281c6a0718SPierre Ossman 		host->cmd->error = MMC_ERR_BADCRC;
9291c6a0718SPierre Ossman 	else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
9301c6a0718SPierre Ossman 		host->cmd->error = MMC_ERR_FAILED;
9311c6a0718SPierre Ossman 
93243b58b36SPierre Ossman 	if (host->cmd->error != MMC_ERR_NONE)
9331c6a0718SPierre Ossman 		tasklet_schedule(&host->finish_tasklet);
93443b58b36SPierre Ossman 	else if (intmask & SDHCI_INT_RESPONSE)
93543b58b36SPierre Ossman 		sdhci_finish_command(host);
9361c6a0718SPierre Ossman }
9371c6a0718SPierre Ossman 
9381c6a0718SPierre Ossman static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
9391c6a0718SPierre Ossman {
9401c6a0718SPierre Ossman 	BUG_ON(intmask == 0);
9411c6a0718SPierre Ossman 
9421c6a0718SPierre Ossman 	if (!host->data) {
9431c6a0718SPierre Ossman 		/*
9441c6a0718SPierre Ossman 		 * A data end interrupt is sent together with the response
9451c6a0718SPierre Ossman 		 * for the stop command.
9461c6a0718SPierre Ossman 		 */
9471c6a0718SPierre Ossman 		if (intmask & SDHCI_INT_DATA_END)
9481c6a0718SPierre Ossman 			return;
9491c6a0718SPierre Ossman 
9501c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Got data interrupt even though no "
9511c6a0718SPierre Ossman 			"data operation was in progress.\n",
9521c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
9531c6a0718SPierre Ossman 		sdhci_dumpregs(host);
9541c6a0718SPierre Ossman 
9551c6a0718SPierre Ossman 		return;
9561c6a0718SPierre Ossman 	}
9571c6a0718SPierre Ossman 
9581c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_DATA_TIMEOUT)
9591c6a0718SPierre Ossman 		host->data->error = MMC_ERR_TIMEOUT;
9601c6a0718SPierre Ossman 	else if (intmask & SDHCI_INT_DATA_CRC)
9611c6a0718SPierre Ossman 		host->data->error = MMC_ERR_BADCRC;
9621c6a0718SPierre Ossman 	else if (intmask & SDHCI_INT_DATA_END_BIT)
9631c6a0718SPierre Ossman 		host->data->error = MMC_ERR_FAILED;
9641c6a0718SPierre Ossman 
9651c6a0718SPierre Ossman 	if (host->data->error != MMC_ERR_NONE)
9661c6a0718SPierre Ossman 		sdhci_finish_data(host);
9671c6a0718SPierre Ossman 	else {
9681c6a0718SPierre Ossman 		if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
9691c6a0718SPierre Ossman 			sdhci_transfer_pio(host);
9701c6a0718SPierre Ossman 
9716ba736a1SPierre Ossman 		/*
9726ba736a1SPierre Ossman 		 * We currently don't do anything fancy with DMA
9736ba736a1SPierre Ossman 		 * boundaries, but as we can't disable the feature
9746ba736a1SPierre Ossman 		 * we need to at least restart the transfer.
9756ba736a1SPierre Ossman 		 */
9766ba736a1SPierre Ossman 		if (intmask & SDHCI_INT_DMA_END)
9776ba736a1SPierre Ossman 			writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
9786ba736a1SPierre Ossman 				host->ioaddr + SDHCI_DMA_ADDRESS);
9796ba736a1SPierre Ossman 
9801c6a0718SPierre Ossman 		if (intmask & SDHCI_INT_DATA_END)
9811c6a0718SPierre Ossman 			sdhci_finish_data(host);
9821c6a0718SPierre Ossman 	}
9831c6a0718SPierre Ossman }
9841c6a0718SPierre Ossman 
9851c6a0718SPierre Ossman static irqreturn_t sdhci_irq(int irq, void *dev_id)
9861c6a0718SPierre Ossman {
9871c6a0718SPierre Ossman 	irqreturn_t result;
9881c6a0718SPierre Ossman 	struct sdhci_host* host = dev_id;
9891c6a0718SPierre Ossman 	u32 intmask;
9901c6a0718SPierre Ossman 
9911c6a0718SPierre Ossman 	spin_lock(&host->lock);
9921c6a0718SPierre Ossman 
9931c6a0718SPierre Ossman 	intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
9941c6a0718SPierre Ossman 
9951c6a0718SPierre Ossman 	if (!intmask || intmask == 0xffffffff) {
9961c6a0718SPierre Ossman 		result = IRQ_NONE;
9971c6a0718SPierre Ossman 		goto out;
9981c6a0718SPierre Ossman 	}
9991c6a0718SPierre Ossman 
10001c6a0718SPierre Ossman 	DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
10011c6a0718SPierre Ossman 
10021c6a0718SPierre Ossman 	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
10031c6a0718SPierre Ossman 		writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
10041c6a0718SPierre Ossman 			host->ioaddr + SDHCI_INT_STATUS);
10051c6a0718SPierre Ossman 		tasklet_schedule(&host->card_tasklet);
10061c6a0718SPierre Ossman 	}
10071c6a0718SPierre Ossman 
10081c6a0718SPierre Ossman 	intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
10091c6a0718SPierre Ossman 
10101c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_CMD_MASK) {
10111c6a0718SPierre Ossman 		writel(intmask & SDHCI_INT_CMD_MASK,
10121c6a0718SPierre Ossman 			host->ioaddr + SDHCI_INT_STATUS);
10131c6a0718SPierre Ossman 		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
10141c6a0718SPierre Ossman 	}
10151c6a0718SPierre Ossman 
10161c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_DATA_MASK) {
10171c6a0718SPierre Ossman 		writel(intmask & SDHCI_INT_DATA_MASK,
10181c6a0718SPierre Ossman 			host->ioaddr + SDHCI_INT_STATUS);
10191c6a0718SPierre Ossman 		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
10201c6a0718SPierre Ossman 	}
10211c6a0718SPierre Ossman 
10221c6a0718SPierre Ossman 	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
10231c6a0718SPierre Ossman 
1024964f9ce2SPierre Ossman 	intmask &= ~SDHCI_INT_ERROR;
1025964f9ce2SPierre Ossman 
10261c6a0718SPierre Ossman 	if (intmask & SDHCI_INT_BUS_POWER) {
10271c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Card is consuming too much power!\n",
10281c6a0718SPierre Ossman 			mmc_hostname(host->mmc));
10291c6a0718SPierre Ossman 		writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
10301c6a0718SPierre Ossman 	}
10311c6a0718SPierre Ossman 
10329d26a5d3SRolf Eike Beer 	intmask &= ~SDHCI_INT_BUS_POWER;
10331c6a0718SPierre Ossman 
10341c6a0718SPierre Ossman 	if (intmask) {
10351c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
10361c6a0718SPierre Ossman 			mmc_hostname(host->mmc), intmask);
10371c6a0718SPierre Ossman 		sdhci_dumpregs(host);
10381c6a0718SPierre Ossman 
10391c6a0718SPierre Ossman 		writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
10401c6a0718SPierre Ossman 	}
10411c6a0718SPierre Ossman 
10421c6a0718SPierre Ossman 	result = IRQ_HANDLED;
10431c6a0718SPierre Ossman 
10441c6a0718SPierre Ossman 	mmiowb();
10451c6a0718SPierre Ossman out:
10461c6a0718SPierre Ossman 	spin_unlock(&host->lock);
10471c6a0718SPierre Ossman 
10481c6a0718SPierre Ossman 	return result;
10491c6a0718SPierre Ossman }
10501c6a0718SPierre Ossman 
10511c6a0718SPierre Ossman /*****************************************************************************\
10521c6a0718SPierre Ossman  *                                                                           *
10531c6a0718SPierre Ossman  * Suspend/resume                                                            *
10541c6a0718SPierre Ossman  *                                                                           *
10551c6a0718SPierre Ossman \*****************************************************************************/
10561c6a0718SPierre Ossman 
10571c6a0718SPierre Ossman #ifdef CONFIG_PM
10581c6a0718SPierre Ossman 
10591c6a0718SPierre Ossman static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
10601c6a0718SPierre Ossman {
10611c6a0718SPierre Ossman 	struct sdhci_chip *chip;
10621c6a0718SPierre Ossman 	int i, ret;
10631c6a0718SPierre Ossman 
10641c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
10651c6a0718SPierre Ossman 	if (!chip)
10661c6a0718SPierre Ossman 		return 0;
10671c6a0718SPierre Ossman 
10681c6a0718SPierre Ossman 	DBG("Suspending...\n");
10691c6a0718SPierre Ossman 
10701c6a0718SPierre Ossman 	for (i = 0;i < chip->num_slots;i++) {
10711c6a0718SPierre Ossman 		if (!chip->hosts[i])
10721c6a0718SPierre Ossman 			continue;
10731c6a0718SPierre Ossman 		ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
10741c6a0718SPierre Ossman 		if (ret) {
10751c6a0718SPierre Ossman 			for (i--;i >= 0;i--)
10761c6a0718SPierre Ossman 				mmc_resume_host(chip->hosts[i]->mmc);
10771c6a0718SPierre Ossman 			return ret;
10781c6a0718SPierre Ossman 		}
10791c6a0718SPierre Ossman 	}
10801c6a0718SPierre Ossman 
10811c6a0718SPierre Ossman 	pci_save_state(pdev);
10821c6a0718SPierre Ossman 	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
10831c6a0718SPierre Ossman 
10841c6a0718SPierre Ossman 	for (i = 0;i < chip->num_slots;i++) {
10851c6a0718SPierre Ossman 		if (!chip->hosts[i])
10861c6a0718SPierre Ossman 			continue;
10871c6a0718SPierre Ossman 		free_irq(chip->hosts[i]->irq, chip->hosts[i]);
10881c6a0718SPierre Ossman 	}
10891c6a0718SPierre Ossman 
10901c6a0718SPierre Ossman 	pci_disable_device(pdev);
10911c6a0718SPierre Ossman 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
10921c6a0718SPierre Ossman 
10931c6a0718SPierre Ossman 	return 0;
10941c6a0718SPierre Ossman }
10951c6a0718SPierre Ossman 
10961c6a0718SPierre Ossman static int sdhci_resume (struct pci_dev *pdev)
10971c6a0718SPierre Ossman {
10981c6a0718SPierre Ossman 	struct sdhci_chip *chip;
10991c6a0718SPierre Ossman 	int i, ret;
11001c6a0718SPierre Ossman 
11011c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
11021c6a0718SPierre Ossman 	if (!chip)
11031c6a0718SPierre Ossman 		return 0;
11041c6a0718SPierre Ossman 
11051c6a0718SPierre Ossman 	DBG("Resuming...\n");
11061c6a0718SPierre Ossman 
11071c6a0718SPierre Ossman 	pci_set_power_state(pdev, PCI_D0);
11081c6a0718SPierre Ossman 	pci_restore_state(pdev);
11091c6a0718SPierre Ossman 	ret = pci_enable_device(pdev);
11101c6a0718SPierre Ossman 	if (ret)
11111c6a0718SPierre Ossman 		return ret;
11121c6a0718SPierre Ossman 
11131c6a0718SPierre Ossman 	for (i = 0;i < chip->num_slots;i++) {
11141c6a0718SPierre Ossman 		if (!chip->hosts[i])
11151c6a0718SPierre Ossman 			continue;
11161c6a0718SPierre Ossman 		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
11171c6a0718SPierre Ossman 			pci_set_master(pdev);
11181c6a0718SPierre Ossman 		ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
11191c6a0718SPierre Ossman 			IRQF_SHARED, chip->hosts[i]->slot_descr,
11201c6a0718SPierre Ossman 			chip->hosts[i]);
11211c6a0718SPierre Ossman 		if (ret)
11221c6a0718SPierre Ossman 			return ret;
11231c6a0718SPierre Ossman 		sdhci_init(chip->hosts[i]);
11241c6a0718SPierre Ossman 		mmiowb();
11251c6a0718SPierre Ossman 		ret = mmc_resume_host(chip->hosts[i]->mmc);
11261c6a0718SPierre Ossman 		if (ret)
11271c6a0718SPierre Ossman 			return ret;
11281c6a0718SPierre Ossman 	}
11291c6a0718SPierre Ossman 
11301c6a0718SPierre Ossman 	return 0;
11311c6a0718SPierre Ossman }
11321c6a0718SPierre Ossman 
11331c6a0718SPierre Ossman #else /* CONFIG_PM */
11341c6a0718SPierre Ossman 
11351c6a0718SPierre Ossman #define sdhci_suspend NULL
11361c6a0718SPierre Ossman #define sdhci_resume NULL
11371c6a0718SPierre Ossman 
11381c6a0718SPierre Ossman #endif /* CONFIG_PM */
11391c6a0718SPierre Ossman 
11401c6a0718SPierre Ossman /*****************************************************************************\
11411c6a0718SPierre Ossman  *                                                                           *
11421c6a0718SPierre Ossman  * Device probing/removal                                                    *
11431c6a0718SPierre Ossman  *                                                                           *
11441c6a0718SPierre Ossman \*****************************************************************************/
11451c6a0718SPierre Ossman 
11461c6a0718SPierre Ossman static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
11471c6a0718SPierre Ossman {
11481c6a0718SPierre Ossman 	int ret;
11491c6a0718SPierre Ossman 	unsigned int version;
11501c6a0718SPierre Ossman 	struct sdhci_chip *chip;
11511c6a0718SPierre Ossman 	struct mmc_host *mmc;
11521c6a0718SPierre Ossman 	struct sdhci_host *host;
11531c6a0718SPierre Ossman 
11541c6a0718SPierre Ossman 	u8 first_bar;
11551c6a0718SPierre Ossman 	unsigned int caps;
11561c6a0718SPierre Ossman 
11571c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
11581c6a0718SPierre Ossman 	BUG_ON(!chip);
11591c6a0718SPierre Ossman 
11601c6a0718SPierre Ossman 	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
11611c6a0718SPierre Ossman 	if (ret)
11621c6a0718SPierre Ossman 		return ret;
11631c6a0718SPierre Ossman 
11641c6a0718SPierre Ossman 	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
11651c6a0718SPierre Ossman 
11661c6a0718SPierre Ossman 	if (first_bar > 5) {
11671c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
11681c6a0718SPierre Ossman 		return -ENODEV;
11691c6a0718SPierre Ossman 	}
11701c6a0718SPierre Ossman 
11711c6a0718SPierre Ossman 	if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
11721c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
11731c6a0718SPierre Ossman 		return -ENODEV;
11741c6a0718SPierre Ossman 	}
11751c6a0718SPierre Ossman 
11761c6a0718SPierre Ossman 	if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
11771c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
11781c6a0718SPierre Ossman 			"You may experience problems.\n");
11791c6a0718SPierre Ossman 	}
11801c6a0718SPierre Ossman 
11811c6a0718SPierre Ossman 	if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
11821c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
11831c6a0718SPierre Ossman 		return -ENODEV;
11841c6a0718SPierre Ossman 	}
11851c6a0718SPierre Ossman 
11861c6a0718SPierre Ossman 	if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
11871c6a0718SPierre Ossman 		printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
11881c6a0718SPierre Ossman 		return -ENODEV;
11891c6a0718SPierre Ossman 	}
11901c6a0718SPierre Ossman 
11911c6a0718SPierre Ossman 	mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
11921c6a0718SPierre Ossman 	if (!mmc)
11931c6a0718SPierre Ossman 		return -ENOMEM;
11941c6a0718SPierre Ossman 
11951c6a0718SPierre Ossman 	host = mmc_priv(mmc);
11961c6a0718SPierre Ossman 	host->mmc = mmc;
11971c6a0718SPierre Ossman 
11981c6a0718SPierre Ossman 	host->chip = chip;
11991c6a0718SPierre Ossman 	chip->hosts[slot] = host;
12001c6a0718SPierre Ossman 
12011c6a0718SPierre Ossman 	host->bar = first_bar + slot;
12021c6a0718SPierre Ossman 
12031c6a0718SPierre Ossman 	host->addr = pci_resource_start(pdev, host->bar);
12041c6a0718SPierre Ossman 	host->irq = pdev->irq;
12051c6a0718SPierre Ossman 
12061c6a0718SPierre Ossman 	DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
12071c6a0718SPierre Ossman 
12081c6a0718SPierre Ossman 	snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
12091c6a0718SPierre Ossman 
12101c6a0718SPierre Ossman 	ret = pci_request_region(pdev, host->bar, host->slot_descr);
12111c6a0718SPierre Ossman 	if (ret)
12121c6a0718SPierre Ossman 		goto free;
12131c6a0718SPierre Ossman 
12141c6a0718SPierre Ossman 	host->ioaddr = ioremap_nocache(host->addr,
12151c6a0718SPierre Ossman 		pci_resource_len(pdev, host->bar));
12161c6a0718SPierre Ossman 	if (!host->ioaddr) {
12171c6a0718SPierre Ossman 		ret = -ENOMEM;
12181c6a0718SPierre Ossman 		goto release;
12191c6a0718SPierre Ossman 	}
12201c6a0718SPierre Ossman 
12211c6a0718SPierre Ossman 	sdhci_reset(host, SDHCI_RESET_ALL);
12221c6a0718SPierre Ossman 
12231c6a0718SPierre Ossman 	version = readw(host->ioaddr + SDHCI_HOST_VERSION);
12241c6a0718SPierre Ossman 	version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
12251c6a0718SPierre Ossman 	if (version != 0) {
12261c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Unknown controller version (%d). "
12271c6a0718SPierre Ossman 			"You may experience problems.\n", host->slot_descr,
12281c6a0718SPierre Ossman 			version);
12291c6a0718SPierre Ossman 	}
12301c6a0718SPierre Ossman 
12311c6a0718SPierre Ossman 	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
12321c6a0718SPierre Ossman 
12331c6a0718SPierre Ossman 	if (debug_nodma)
12341c6a0718SPierre Ossman 		DBG("DMA forced off\n");
12351c6a0718SPierre Ossman 	else if (debug_forcedma) {
12361c6a0718SPierre Ossman 		DBG("DMA forced on\n");
12371c6a0718SPierre Ossman 		host->flags |= SDHCI_USE_DMA;
12381c6a0718SPierre Ossman 	} else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
12391c6a0718SPierre Ossman 		host->flags |= SDHCI_USE_DMA;
12401c6a0718SPierre Ossman 	else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
12411c6a0718SPierre Ossman 		DBG("Controller doesn't have DMA interface\n");
12421c6a0718SPierre Ossman 	else if (!(caps & SDHCI_CAN_DO_DMA))
12431c6a0718SPierre Ossman 		DBG("Controller doesn't have DMA capability\n");
12441c6a0718SPierre Ossman 	else
12451c6a0718SPierre Ossman 		host->flags |= SDHCI_USE_DMA;
12461c6a0718SPierre Ossman 
12471c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA) {
12481c6a0718SPierre Ossman 		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
12491c6a0718SPierre Ossman 			printk(KERN_WARNING "%s: No suitable DMA available. "
12501c6a0718SPierre Ossman 				"Falling back to PIO.\n", host->slot_descr);
12511c6a0718SPierre Ossman 			host->flags &= ~SDHCI_USE_DMA;
12521c6a0718SPierre Ossman 		}
12531c6a0718SPierre Ossman 	}
12541c6a0718SPierre Ossman 
12551c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA)
12561c6a0718SPierre Ossman 		pci_set_master(pdev);
12571c6a0718SPierre Ossman 	else /* XXX: Hack to get MMC layer to avoid highmem */
12581c6a0718SPierre Ossman 		pdev->dma_mask = 0;
12591c6a0718SPierre Ossman 
12601c6a0718SPierre Ossman 	host->max_clk =
12611c6a0718SPierre Ossman 		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
12621c6a0718SPierre Ossman 	if (host->max_clk == 0) {
12631c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Hardware doesn't specify base clock "
12641c6a0718SPierre Ossman 			"frequency.\n", host->slot_descr);
12651c6a0718SPierre Ossman 		ret = -ENODEV;
12661c6a0718SPierre Ossman 		goto unmap;
12671c6a0718SPierre Ossman 	}
12681c6a0718SPierre Ossman 	host->max_clk *= 1000000;
12691c6a0718SPierre Ossman 
12701c6a0718SPierre Ossman 	host->timeout_clk =
12711c6a0718SPierre Ossman 		(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
12721c6a0718SPierre Ossman 	if (host->timeout_clk == 0) {
12731c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
12741c6a0718SPierre Ossman 			"frequency.\n", host->slot_descr);
12751c6a0718SPierre Ossman 		ret = -ENODEV;
12761c6a0718SPierre Ossman 		goto unmap;
12771c6a0718SPierre Ossman 	}
12781c6a0718SPierre Ossman 	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
12791c6a0718SPierre Ossman 		host->timeout_clk *= 1000;
12801c6a0718SPierre Ossman 
12811c6a0718SPierre Ossman 	/*
12821c6a0718SPierre Ossman 	 * Set host parameters.
12831c6a0718SPierre Ossman 	 */
12841c6a0718SPierre Ossman 	mmc->ops = &sdhci_ops;
12851c6a0718SPierre Ossman 	mmc->f_min = host->max_clk / 256;
12861c6a0718SPierre Ossman 	mmc->f_max = host->max_clk;
12871c6a0718SPierre Ossman 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
12881c6a0718SPierre Ossman 
12891c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_DO_HISPD)
12901c6a0718SPierre Ossman 		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
12911c6a0718SPierre Ossman 
12921c6a0718SPierre Ossman 	mmc->ocr_avail = 0;
12931c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_VDD_330)
12941c6a0718SPierre Ossman 		mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
12951c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_VDD_300)
12961c6a0718SPierre Ossman 		mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
12971c6a0718SPierre Ossman 	if (caps & SDHCI_CAN_VDD_180)
129855556da0SPhilip Langdale 		mmc->ocr_avail |= MMC_VDD_165_195;
12991c6a0718SPierre Ossman 
13001c6a0718SPierre Ossman 	if (mmc->ocr_avail == 0) {
13011c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Hardware doesn't report any "
13021c6a0718SPierre Ossman 			"support voltages.\n", host->slot_descr);
13031c6a0718SPierre Ossman 		ret = -ENODEV;
13041c6a0718SPierre Ossman 		goto unmap;
13051c6a0718SPierre Ossman 	}
13061c6a0718SPierre Ossman 
13071c6a0718SPierre Ossman 	spin_lock_init(&host->lock);
13081c6a0718SPierre Ossman 
13091c6a0718SPierre Ossman 	/*
13101c6a0718SPierre Ossman 	 * Maximum number of segments. Hardware cannot do scatter lists.
13111c6a0718SPierre Ossman 	 */
13121c6a0718SPierre Ossman 	if (host->flags & SDHCI_USE_DMA)
13131c6a0718SPierre Ossman 		mmc->max_hw_segs = 1;
13141c6a0718SPierre Ossman 	else
13151c6a0718SPierre Ossman 		mmc->max_hw_segs = 16;
13161c6a0718SPierre Ossman 	mmc->max_phys_segs = 16;
13171c6a0718SPierre Ossman 
13181c6a0718SPierre Ossman 	/*
13191c6a0718SPierre Ossman 	 * Maximum number of sectors in one transfer. Limited by DMA boundary
13201c6a0718SPierre Ossman 	 * size (512KiB).
13211c6a0718SPierre Ossman 	 */
13221c6a0718SPierre Ossman 	mmc->max_req_size = 524288;
13231c6a0718SPierre Ossman 
13241c6a0718SPierre Ossman 	/*
13251c6a0718SPierre Ossman 	 * Maximum segment size. Could be one segment with the maximum number
13261c6a0718SPierre Ossman 	 * of bytes.
13271c6a0718SPierre Ossman 	 */
13281c6a0718SPierre Ossman 	mmc->max_seg_size = mmc->max_req_size;
13291c6a0718SPierre Ossman 
13301c6a0718SPierre Ossman 	/*
13311c6a0718SPierre Ossman 	 * Maximum block size. This varies from controller to controller and
13321c6a0718SPierre Ossman 	 * is specified in the capabilities register.
13331c6a0718SPierre Ossman 	 */
13341c6a0718SPierre Ossman 	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
13351c6a0718SPierre Ossman 	if (mmc->max_blk_size >= 3) {
13361c6a0718SPierre Ossman 		printk(KERN_ERR "%s: Invalid maximum block size.\n",
13371c6a0718SPierre Ossman 			host->slot_descr);
13381c6a0718SPierre Ossman 		ret = -ENODEV;
13391c6a0718SPierre Ossman 		goto unmap;
13401c6a0718SPierre Ossman 	}
13411c6a0718SPierre Ossman 	mmc->max_blk_size = 512 << mmc->max_blk_size;
13421c6a0718SPierre Ossman 
13431c6a0718SPierre Ossman 	/*
13441c6a0718SPierre Ossman 	 * Maximum block count.
13451c6a0718SPierre Ossman 	 */
13461c6a0718SPierre Ossman 	mmc->max_blk_count = 65535;
13471c6a0718SPierre Ossman 
13481c6a0718SPierre Ossman 	/*
13491c6a0718SPierre Ossman 	 * Init tasklets.
13501c6a0718SPierre Ossman 	 */
13511c6a0718SPierre Ossman 	tasklet_init(&host->card_tasklet,
13521c6a0718SPierre Ossman 		sdhci_tasklet_card, (unsigned long)host);
13531c6a0718SPierre Ossman 	tasklet_init(&host->finish_tasklet,
13541c6a0718SPierre Ossman 		sdhci_tasklet_finish, (unsigned long)host);
13551c6a0718SPierre Ossman 
13561c6a0718SPierre Ossman 	setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
13571c6a0718SPierre Ossman 
13581c6a0718SPierre Ossman 	ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
13591c6a0718SPierre Ossman 		host->slot_descr, host);
13601c6a0718SPierre Ossman 	if (ret)
13611c6a0718SPierre Ossman 		goto untasklet;
13621c6a0718SPierre Ossman 
13631c6a0718SPierre Ossman 	sdhci_init(host);
13641c6a0718SPierre Ossman 
13651c6a0718SPierre Ossman #ifdef CONFIG_MMC_DEBUG
13661c6a0718SPierre Ossman 	sdhci_dumpregs(host);
13671c6a0718SPierre Ossman #endif
13681c6a0718SPierre Ossman 
13691c6a0718SPierre Ossman 	mmiowb();
13701c6a0718SPierre Ossman 
13711c6a0718SPierre Ossman 	mmc_add_host(mmc);
13721c6a0718SPierre Ossman 
13731c6a0718SPierre Ossman 	printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
13741c6a0718SPierre Ossman 		host->addr, host->irq,
13751c6a0718SPierre Ossman 		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
13761c6a0718SPierre Ossman 
13771c6a0718SPierre Ossman 	return 0;
13781c6a0718SPierre Ossman 
13791c6a0718SPierre Ossman untasklet:
13801c6a0718SPierre Ossman 	tasklet_kill(&host->card_tasklet);
13811c6a0718SPierre Ossman 	tasklet_kill(&host->finish_tasklet);
13821c6a0718SPierre Ossman unmap:
13831c6a0718SPierre Ossman 	iounmap(host->ioaddr);
13841c6a0718SPierre Ossman release:
13851c6a0718SPierre Ossman 	pci_release_region(pdev, host->bar);
13861c6a0718SPierre Ossman free:
13871c6a0718SPierre Ossman 	mmc_free_host(mmc);
13881c6a0718SPierre Ossman 
13891c6a0718SPierre Ossman 	return ret;
13901c6a0718SPierre Ossman }
13911c6a0718SPierre Ossman 
13921c6a0718SPierre Ossman static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
13931c6a0718SPierre Ossman {
13941c6a0718SPierre Ossman 	struct sdhci_chip *chip;
13951c6a0718SPierre Ossman 	struct mmc_host *mmc;
13961c6a0718SPierre Ossman 	struct sdhci_host *host;
13971c6a0718SPierre Ossman 
13981c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
13991c6a0718SPierre Ossman 	host = chip->hosts[slot];
14001c6a0718SPierre Ossman 	mmc = host->mmc;
14011c6a0718SPierre Ossman 
14021c6a0718SPierre Ossman 	chip->hosts[slot] = NULL;
14031c6a0718SPierre Ossman 
14041c6a0718SPierre Ossman 	mmc_remove_host(mmc);
14051c6a0718SPierre Ossman 
14061c6a0718SPierre Ossman 	sdhci_reset(host, SDHCI_RESET_ALL);
14071c6a0718SPierre Ossman 
14081c6a0718SPierre Ossman 	free_irq(host->irq, host);
14091c6a0718SPierre Ossman 
14101c6a0718SPierre Ossman 	del_timer_sync(&host->timer);
14111c6a0718SPierre Ossman 
14121c6a0718SPierre Ossman 	tasklet_kill(&host->card_tasklet);
14131c6a0718SPierre Ossman 	tasklet_kill(&host->finish_tasklet);
14141c6a0718SPierre Ossman 
14151c6a0718SPierre Ossman 	iounmap(host->ioaddr);
14161c6a0718SPierre Ossman 
14171c6a0718SPierre Ossman 	pci_release_region(pdev, host->bar);
14181c6a0718SPierre Ossman 
14191c6a0718SPierre Ossman 	mmc_free_host(mmc);
14201c6a0718SPierre Ossman }
14211c6a0718SPierre Ossman 
14221c6a0718SPierre Ossman static int __devinit sdhci_probe(struct pci_dev *pdev,
14231c6a0718SPierre Ossman 	const struct pci_device_id *ent)
14241c6a0718SPierre Ossman {
14251c6a0718SPierre Ossman 	int ret, i;
14261c6a0718SPierre Ossman 	u8 slots, rev;
14271c6a0718SPierre Ossman 	struct sdhci_chip *chip;
14281c6a0718SPierre Ossman 
14291c6a0718SPierre Ossman 	BUG_ON(pdev == NULL);
14301c6a0718SPierre Ossman 	BUG_ON(ent == NULL);
14311c6a0718SPierre Ossman 
14321c6a0718SPierre Ossman 	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
14331c6a0718SPierre Ossman 
14341c6a0718SPierre Ossman 	printk(KERN_INFO DRIVER_NAME
14351c6a0718SPierre Ossman 		": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
14361c6a0718SPierre Ossman 		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
14371c6a0718SPierre Ossman 		(int)rev);
14381c6a0718SPierre Ossman 
14391c6a0718SPierre Ossman 	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
14401c6a0718SPierre Ossman 	if (ret)
14411c6a0718SPierre Ossman 		return ret;
14421c6a0718SPierre Ossman 
14431c6a0718SPierre Ossman 	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
14441c6a0718SPierre Ossman 	DBG("found %d slot(s)\n", slots);
14451c6a0718SPierre Ossman 	if (slots == 0)
14461c6a0718SPierre Ossman 		return -ENODEV;
14471c6a0718SPierre Ossman 
14481c6a0718SPierre Ossman 	ret = pci_enable_device(pdev);
14491c6a0718SPierre Ossman 	if (ret)
14501c6a0718SPierre Ossman 		return ret;
14511c6a0718SPierre Ossman 
14521c6a0718SPierre Ossman 	chip = kzalloc(sizeof(struct sdhci_chip) +
14531c6a0718SPierre Ossman 		sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
14541c6a0718SPierre Ossman 	if (!chip) {
14551c6a0718SPierre Ossman 		ret = -ENOMEM;
14561c6a0718SPierre Ossman 		goto err;
14571c6a0718SPierre Ossman 	}
14581c6a0718SPierre Ossman 
14591c6a0718SPierre Ossman 	chip->pdev = pdev;
14601c6a0718SPierre Ossman 	chip->quirks = ent->driver_data;
14611c6a0718SPierre Ossman 
14621c6a0718SPierre Ossman 	if (debug_quirks)
14631c6a0718SPierre Ossman 		chip->quirks = debug_quirks;
14641c6a0718SPierre Ossman 
14651c6a0718SPierre Ossman 	chip->num_slots = slots;
14661c6a0718SPierre Ossman 	pci_set_drvdata(pdev, chip);
14671c6a0718SPierre Ossman 
14681c6a0718SPierre Ossman 	for (i = 0;i < slots;i++) {
14691c6a0718SPierre Ossman 		ret = sdhci_probe_slot(pdev, i);
14701c6a0718SPierre Ossman 		if (ret) {
14711c6a0718SPierre Ossman 			for (i--;i >= 0;i--)
14721c6a0718SPierre Ossman 				sdhci_remove_slot(pdev, i);
14731c6a0718SPierre Ossman 			goto free;
14741c6a0718SPierre Ossman 		}
14751c6a0718SPierre Ossman 	}
14761c6a0718SPierre Ossman 
14771c6a0718SPierre Ossman 	return 0;
14781c6a0718SPierre Ossman 
14791c6a0718SPierre Ossman free:
14801c6a0718SPierre Ossman 	pci_set_drvdata(pdev, NULL);
14811c6a0718SPierre Ossman 	kfree(chip);
14821c6a0718SPierre Ossman 
14831c6a0718SPierre Ossman err:
14841c6a0718SPierre Ossman 	pci_disable_device(pdev);
14851c6a0718SPierre Ossman 	return ret;
14861c6a0718SPierre Ossman }
14871c6a0718SPierre Ossman 
14881c6a0718SPierre Ossman static void __devexit sdhci_remove(struct pci_dev *pdev)
14891c6a0718SPierre Ossman {
14901c6a0718SPierre Ossman 	int i;
14911c6a0718SPierre Ossman 	struct sdhci_chip *chip;
14921c6a0718SPierre Ossman 
14931c6a0718SPierre Ossman 	chip = pci_get_drvdata(pdev);
14941c6a0718SPierre Ossman 
14951c6a0718SPierre Ossman 	if (chip) {
14961c6a0718SPierre Ossman 		for (i = 0;i < chip->num_slots;i++)
14971c6a0718SPierre Ossman 			sdhci_remove_slot(pdev, i);
14981c6a0718SPierre Ossman 
14991c6a0718SPierre Ossman 		pci_set_drvdata(pdev, NULL);
15001c6a0718SPierre Ossman 
15011c6a0718SPierre Ossman 		kfree(chip);
15021c6a0718SPierre Ossman 	}
15031c6a0718SPierre Ossman 
15041c6a0718SPierre Ossman 	pci_disable_device(pdev);
15051c6a0718SPierre Ossman }
15061c6a0718SPierre Ossman 
15071c6a0718SPierre Ossman static struct pci_driver sdhci_driver = {
15081c6a0718SPierre Ossman 	.name = 	DRIVER_NAME,
15091c6a0718SPierre Ossman 	.id_table =	pci_ids,
15101c6a0718SPierre Ossman 	.probe = 	sdhci_probe,
15111c6a0718SPierre Ossman 	.remove =	__devexit_p(sdhci_remove),
15121c6a0718SPierre Ossman 	.suspend =	sdhci_suspend,
15131c6a0718SPierre Ossman 	.resume	=	sdhci_resume,
15141c6a0718SPierre Ossman };
15151c6a0718SPierre Ossman 
15161c6a0718SPierre Ossman /*****************************************************************************\
15171c6a0718SPierre Ossman  *                                                                           *
15181c6a0718SPierre Ossman  * Driver init/exit                                                          *
15191c6a0718SPierre Ossman  *                                                                           *
15201c6a0718SPierre Ossman \*****************************************************************************/
15211c6a0718SPierre Ossman 
15221c6a0718SPierre Ossman static int __init sdhci_drv_init(void)
15231c6a0718SPierre Ossman {
15241c6a0718SPierre Ossman 	printk(KERN_INFO DRIVER_NAME
15251c6a0718SPierre Ossman 		": Secure Digital Host Controller Interface driver\n");
15261c6a0718SPierre Ossman 	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
15271c6a0718SPierre Ossman 
15281c6a0718SPierre Ossman 	return pci_register_driver(&sdhci_driver);
15291c6a0718SPierre Ossman }
15301c6a0718SPierre Ossman 
15311c6a0718SPierre Ossman static void __exit sdhci_drv_exit(void)
15321c6a0718SPierre Ossman {
15331c6a0718SPierre Ossman 	DBG("Exiting\n");
15341c6a0718SPierre Ossman 
15351c6a0718SPierre Ossman 	pci_unregister_driver(&sdhci_driver);
15361c6a0718SPierre Ossman }
15371c6a0718SPierre Ossman 
15381c6a0718SPierre Ossman module_init(sdhci_drv_init);
15391c6a0718SPierre Ossman module_exit(sdhci_drv_exit);
15401c6a0718SPierre Ossman 
15411c6a0718SPierre Ossman module_param(debug_nodma, uint, 0444);
15421c6a0718SPierre Ossman module_param(debug_forcedma, uint, 0444);
15431c6a0718SPierre Ossman module_param(debug_quirks, uint, 0444);
15441c6a0718SPierre Ossman 
15451c6a0718SPierre Ossman MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
15461c6a0718SPierre Ossman MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
15471c6a0718SPierre Ossman MODULE_LICENSE("GPL");
15481c6a0718SPierre Ossman 
15491c6a0718SPierre Ossman MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
15501c6a0718SPierre Ossman MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
15511c6a0718SPierre Ossman MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
1552