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