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