sdhci.c revision d6f8deecefc133cac044f6029bdb349a1cb8753a
1d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*
270f10482c668301c483acded13bf68780ad352b9Pierre Ossman *  linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
3d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *
414d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
5d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *
6d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * This program is free software; you can redistribute it and/or modify
7643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * it under the terms of the GNU General Public License as published by
8643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * the Free Software Foundation; either version 2 of the License, or (at
9643f720cea989d2913fc0120a2384fecc1be1f9aPierre Ossman * your option) any later version.
10d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman */
11d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
12d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/delay.h>
13d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/highmem.h>
14d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/pci.h>
15d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/dma-mapping.h>
16d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
17d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <linux/mmc/host.h>
18d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
19d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include <asm/scatterlist.h>
20d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
21d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#include "sdhci.h"
22d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
23d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define DRIVER_NAME "sdhci"
24d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
25d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define DBG(f, x...) \
26c65631781eb0f2e81865017c1484e9aef76e1b61Russell King	pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
27d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
28df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossmanstatic unsigned int debug_quirks = 0;
296743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman
30645289dca5021224279e67b4655796cafdfdad00Pierre Ossman#define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
3198608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman#define SDHCI_QUIRK_FORCE_DMA				(1<<1)
328a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman/* Controller doesn't like some resets when there is no card inserted. */
338a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman#define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
349e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
35b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
367c168e3db7d900008ee304574057e0dc1a8505afFeng Tang#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
37645289dca5021224279e67b4655796cafdfdad00Pierre Ossman
38d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic const struct pci_device_id pci_ids[] __devinitdata = {
39645289dca5021224279e67b4655796cafdfdad00Pierre Ossman	{
40645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		.vendor		= PCI_VENDOR_ID_RICOH,
41645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		.device		= PCI_DEVICE_ID_RICOH_R5C822,
42645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		.subvendor	= PCI_VENDOR_ID_IBM,
43645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		.subdevice	= PCI_ANY_ID,
4498608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.driver_data	= SDHCI_QUIRK_CLOCK_BEFORE_RESET |
4598608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman				  SDHCI_QUIRK_FORCE_DMA,
4698608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman	},
4798608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman
4898608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman	{
4998608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.vendor		= PCI_VENDOR_ID_RICOH,
5098608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.device		= PCI_DEVICE_ID_RICOH_R5C822,
5198608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.subvendor	= PCI_ANY_ID,
5298608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.subdevice	= PCI_ANY_ID,
538a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
548a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman				  SDHCI_QUIRK_NO_CARD_NO_RESET,
5598608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman	},
5698608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman
5798608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman	{
5898608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.vendor		= PCI_VENDOR_ID_TI,
5998608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.device		= PCI_DEVICE_ID_TI_XX21_XX11_SD,
6098608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.subvendor	= PCI_ANY_ID,
6198608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.subdevice	= PCI_ANY_ID,
6298608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
63645289dca5021224279e67b4655796cafdfdad00Pierre Ossman	},
64645289dca5021224279e67b4655796cafdfdad00Pierre Ossman
659e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	{
669e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt		.vendor		= PCI_VENDOR_ID_ENE,
679e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
689e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt		.subvendor	= PCI_ANY_ID,
699e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt		.subdevice	= PCI_ANY_ID,
707c168e3db7d900008ee304574057e0dc1a8505afFeng Tang		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
717c168e3db7d900008ee304574057e0dc1a8505afFeng Tang				  SDHCI_QUIRK_BROKEN_DMA,
729e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	},
739e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt
747de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov	{
757de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov		.vendor		= PCI_VENDOR_ID_ENE,
767de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov		.device		= PCI_DEVICE_ID_ENE_CB712_SD_2,
777de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov		.subvendor	= PCI_ANY_ID,
787de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov		.subdevice	= PCI_ANY_ID,
797c168e3db7d900008ee304574057e0dc1a8505afFeng Tang		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
807c168e3db7d900008ee304574057e0dc1a8505afFeng Tang				  SDHCI_QUIRK_BROKEN_DMA,
817de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov	},
827de064ebc67d9baf6c933d3a7046feb9b4eced05Milko Krachounov
83b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	{
84b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.vendor         = PCI_VENDOR_ID_ENE,
85b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.device         = PCI_DEVICE_ID_ENE_CB714_SD,
86b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.subvendor      = PCI_ANY_ID,
87b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.subdevice      = PCI_ANY_ID,
88b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
89b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
90b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	},
91b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo
92b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	{
93b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.vendor         = PCI_VENDOR_ID_ENE,
94b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.device         = PCI_DEVICE_ID_ENE_CB714_SD_2,
95b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.subvendor      = PCI_ANY_ID,
96b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.subdevice      = PCI_ANY_ID,
97b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
98b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
99b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	},
100b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo
101645289dca5021224279e67b4655796cafdfdad00Pierre Ossman	{	/* Generic SD host controller */
102645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
103645289dca5021224279e67b4655796cafdfdad00Pierre Ossman	},
104645289dca5021224279e67b4655796cafdfdad00Pierre Ossman
105d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	{ /* end: all zeroes */ },
106d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman};
107d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
108d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_DEVICE_TABLE(pci, pci_ids);
109d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
110d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
111d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_data(struct sdhci_host *);
112d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
113d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
114d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_command(struct sdhci_host *);
115d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
116d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_dumpregs(struct sdhci_host *host)
117d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
118d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
119d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
120d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
121d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_DMA_ADDRESS),
122d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readw(host->ioaddr + SDHCI_HOST_VERSION));
123d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
124d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readw(host->ioaddr + SDHCI_BLOCK_SIZE),
125d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readw(host->ioaddr + SDHCI_BLOCK_COUNT));
126d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
127d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_ARGUMENT),
128d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readw(host->ioaddr + SDHCI_TRANSFER_MODE));
129d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
130d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_PRESENT_STATE),
131d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readb(host->ioaddr + SDHCI_HOST_CONTROL));
132d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
133d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readb(host->ioaddr + SDHCI_POWER_CONTROL),
134d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
135d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
1362df3b71b2746469b5b344cf7da5facecd4110cc9Nicolas Pitre		readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL),
137d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
138d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
139d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
140d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_INT_STATUS));
141d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
142d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_INT_ENABLE),
143d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
144d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
145d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readw(host->ioaddr + SDHCI_ACMD12_ERR),
146d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
147d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
148d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_CAPABILITIES),
149d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		readl(host->ioaddr + SDHCI_MAX_CURRENT));
150d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
151d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
152d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
153d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
154d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
155d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
156d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Low level functions                                                       *
157d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
158d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
159d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
160d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_reset(struct sdhci_host *host, u8 mask)
161d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
162e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman	unsigned long timeout;
163e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman
1648a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman	if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
1658a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman		if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
1668a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman			SDHCI_CARD_PRESENT))
1678a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman			return;
1688a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman	}
1698a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman
170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
172e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman	if (mask & SDHCI_RESET_ALL)
173d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->clock = 0;
174d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
175e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman	/* Wait max 100 ms */
176e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman	timeout = 100;
177e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman
178e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman	/* hw clears the bit when it's done */
179e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman	while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
180e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman		if (timeout == 0) {
181acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman			printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
182e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman				mmc_hostname(host->mmc), (int)mask);
183e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman			sdhci_dumpregs(host);
184e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman			return;
185e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman		}
186e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman		timeout--;
187e16514d8d86ecbde18a2a7495cf028861b34c157Pierre Ossman		mdelay(1);
188d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
189d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
190d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
191d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_init(struct sdhci_host *host)
192d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
193d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u32 intmask;
194d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
195d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_reset(host, SDHCI_RESET_ALL);
196d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1973192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman	intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
1983192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
1993192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
2003192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
201a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
2023192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
203d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
204d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
205d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
206d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
207d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
208d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_activate_led(struct sdhci_host *host)
209d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
210d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u8 ctrl;
211d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
212d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
213d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ctrl |= SDHCI_CTRL_LED;
214d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
215d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
216d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
217d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_deactivate_led(struct sdhci_host *host)
218d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
219d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u8 ctrl;
220d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
221d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
222d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ctrl &= ~SDHCI_CTRL_LED;
223d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
224d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
225d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
226d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
227d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
228d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Core functions                                                            *
229d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
230d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
231d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
2322a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossmanstatic inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
233d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
2342a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman	return page_address(host->cur_sg->page) + host->cur_sg->offset;
235d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
236d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
237d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic inline int sdhci_next_sg(struct sdhci_host* host)
238d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
239d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
240d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Skip to next SG entry.
241d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
242d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->cur_sg++;
243d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->num_sg--;
244d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
245d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
246d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Any entries left?
247d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
248d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->num_sg > 0) {
249d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->offset = 0;
250d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->remain = host->cur_sg->length;
251d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
252d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
253d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return host->num_sg;
254d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
255d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
256a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_read_block_pio(struct sdhci_host *host)
257d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
258a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	int blksize, chunk_remain;
259a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	u32 data;
260d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	char *buffer;
261a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	int size;
262d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
263a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	DBG("PIO reading\n");
264d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
265a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	blksize = host->data->blksz;
266a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	chunk_remain = 0;
267a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	data = 0;
268d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
2692a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman	buffer = sdhci_sg_to_buffer(host) + host->offset;
270d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
271a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	while (blksize) {
272a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		if (chunk_remain == 0) {
273a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			data = readl(host->ioaddr + SDHCI_BUFFER);
274a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			chunk_remain = min(blksize, 4);
275a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		}
276d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
27714d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov		size = min(host->remain, chunk_remain);
278d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
279a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		chunk_remain -= size;
280a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		blksize -= size;
281a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		host->offset += size;
282a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		host->remain -= size;
28314d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov
284a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		while (size) {
285a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			*buffer = data & 0xFF;
286a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			buffer++;
287a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			data >>= 8;
288a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			size--;
289a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		}
290d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
291a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		if (host->remain == 0) {
292a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			if (sdhci_next_sg(host) == 0) {
293a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman				BUG_ON(blksize != 0);
294a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman				return;
295a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			}
2962a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman			buffer = sdhci_sg_to_buffer(host);
297d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
298a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	}
299a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman}
300d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
301a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_write_block_pio(struct sdhci_host *host)
302a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{
303a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	int blksize, chunk_remain;
304a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	u32 data;
305a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	char *buffer;
306a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	int bytes, size;
307d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
308a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	DBG("PIO writing\n");
309a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
310a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	blksize = host->data->blksz;
311a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	chunk_remain = 4;
312a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	data = 0;
313d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
314a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	bytes = 0;
3152a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman	buffer = sdhci_sg_to_buffer(host) + host->offset;
316d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
317a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	while (blksize) {
31814d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov		size = min(host->remain, chunk_remain);
319a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
320a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		chunk_remain -= size;
321a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		blksize -= size;
322d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->offset += size;
323d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->remain -= size;
32414d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov
325a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		while (size) {
326a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			data >>= 8;
327a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			data |= (u32)*buffer << 24;
328a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			buffer++;
329a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			size--;
330a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		}
331a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
332a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		if (chunk_remain == 0) {
333a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			writel(data, host->ioaddr + SDHCI_BUFFER);
334a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			chunk_remain = min(blksize, 4);
335a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		}
336d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
337d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (host->remain == 0) {
338d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			if (sdhci_next_sg(host) == 0) {
339a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman				BUG_ON(blksize != 0);
340d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				return;
341d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			}
3422a22b14edfdf1dce303ec48bb934a6a2edb278b5Pierre Ossman			buffer = sdhci_sg_to_buffer(host);
343d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
344d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
345a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman}
346a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
347a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossmanstatic void sdhci_transfer_pio(struct sdhci_host *host)
348a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman{
349a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	u32 mask;
350a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
351a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	BUG_ON(!host->data);
352a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
35314d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov	if (host->num_sg == 0)
354a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		return;
355a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
356a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	if (host->data->flags & MMC_DATA_READ)
357a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		mask = SDHCI_DATA_AVAILABLE;
358a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	else
359a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		mask = SDHCI_SPACE_AVAILABLE;
360a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman
361a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
362a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		if (host->data->flags & MMC_DATA_READ)
363a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			sdhci_read_block_pio(host);
364a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		else
365a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			sdhci_write_block_pio(host);
366d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
36714d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov		if (host->num_sg == 0)
368a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman			break;
369a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	}
370d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
371a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman	DBG("PIO transfer complete.\n");
372d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
373d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
374d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
375d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
3761c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	u8 count;
3771c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	unsigned target_timeout, current_timeout;
378d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
379d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	WARN_ON(host->data);
380d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
381c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	if (data == NULL)
382d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return;
383d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
384bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman	/* Sanity checks */
385bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman	BUG_ON(data->blksz * data->blocks > 524288);
386fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	BUG_ON(data->blksz > host->mmc->max_blk_size);
3871d676e02970d9e511c9b96101501da90954ee265Pierre Ossman	BUG_ON(data->blocks > 65535);
388d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
389e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman	host->data = data;
390e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman	host->data_early = 0;
391e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman
3921c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	/* timeout in us */
3931c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	target_timeout = data->timeout_ns / 1000 +
3941c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		data->timeout_clks / host->clock;
395d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
3961c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	/*
3971c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 * Figure out needed cycles.
3981c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 * We do this in steps in order to fit inside a 32 bit int.
3991c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 * The first step is the minimum timeout, which will have a
4001c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 * minimum resolution of 6 bits:
4011c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 * (1) 2^13*1000 > 2^22,
4021c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 * (2) host->timeout_clk < 2^16
4031c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 *     =>
4041c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 *     (1) / (2) > 2^6
4051c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	 */
4061c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	count = 0;
4071c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
4081c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	while (current_timeout < target_timeout) {
4091c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		count++;
4101c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		current_timeout <<= 1;
4111c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		if (count >= 0xF)
4121c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman			break;
4131c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	}
4141c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman
4151c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	if (count >= 0xF) {
4161c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		printk(KERN_WARNING "%s: Too large timeout requested!\n",
4171c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman			mmc_hostname(host->mmc));
4181c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		count = 0xE;
4191c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	}
4201c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman
4211c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
422d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
423d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->flags & SDHCI_USE_DMA) {
424d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		int count;
425d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
426d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
427d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
428d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		BUG_ON(count != 1);
429d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
430d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
431d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	} else {
432d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->cur_sg = data->sg;
433d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->num_sg = data->sg_len;
434d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
435d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->offset = 0;
436d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->remain = host->cur_sg->length;
437d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
438c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman
439bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman	/* We do not handle DMA boundaries, so set it to max (512 KiB) */
440bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman	writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
441bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman		host->ioaddr + SDHCI_BLOCK_SIZE);
442c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
443c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman}
444c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman
445c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossmanstatic void sdhci_set_transfer_mode(struct sdhci_host *host,
446c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	struct mmc_data *data)
447c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman{
448c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	u16 mode;
449c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman
450c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	if (data == NULL)
451c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman		return;
452c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman
453e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman	WARN_ON(!host->data);
454e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman
455c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	mode = SDHCI_TRNS_BLK_CNT_EN;
456c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	if (data->blocks > 1)
457c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman		mode |= SDHCI_TRNS_MULTI;
458c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	if (data->flags & MMC_DATA_READ)
459c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman		mode |= SDHCI_TRNS_READ;
460c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	if (host->flags & SDHCI_USE_DMA)
461c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman		mode |= SDHCI_TRNS_DMA;
462c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman
463c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
464d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
465d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
466d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_data(struct sdhci_host *host)
467d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
468d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct mmc_data *data;
469d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u16 blocks;
470d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
471d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	BUG_ON(!host->data);
472d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
473d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	data = host->data;
474d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->data = NULL;
475d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
476d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->flags & SDHCI_USE_DMA) {
477d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
478d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
479d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
480d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
481d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
482d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Controller doesn't count down when in single block mode.
483d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
4842b061973404802fb87db93175b856ee0dfbe38e4Pierre Ossman	if (data->blocks == 1)
48517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		blocks = (data->error == 0) ? 0 : 1;
486d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else
487d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
488a3fd4a1b9ced850ac1a9d5bb9f8fab494d07f3faRussell King	data->bytes_xfered = data->blksz * (data->blocks - blocks);
489d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
49017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (!data->error && blocks) {
491d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		printk(KERN_ERR "%s: Controller signalled completion even "
492acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman			"though there were blocks left.\n",
493acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman			mmc_hostname(host->mmc));
49417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		data->error = -EIO;
495d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
496d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
497d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (data->stop) {
498d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		/*
499d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		 * The controller needs a reset of internal state machines
500d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		 * upon error conditions.
501d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		 */
50217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		if (data->error) {
503d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_reset(host, SDHCI_RESET_CMD);
504d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_reset(host, SDHCI_RESET_DATA);
505d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
506d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
507d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_send_command(host, data->stop);
508d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	} else
509d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		tasklet_schedule(&host->finish_tasklet);
510d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
511d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
512d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
513d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
514d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int flags;
515fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman	u32 mask;
5167cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman	unsigned long timeout;
517d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
518d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	WARN_ON(host->cmd);
519d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
520d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/* Wait max 10 ms */
5217cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman	timeout = 10;
522fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman
523fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman	mask = SDHCI_CMD_INHIBIT;
524fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman	if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
525fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman		mask |= SDHCI_DATA_INHIBIT;
526fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman
527fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman	/* We shouldn't wait for data inihibit for stop commands, even
528fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman	   though they might use busy signaling */
529fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman	if (host->mrq->data && (cmd == host->mrq->data->stop))
530fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman		mask &= ~SDHCI_DATA_INHIBIT;
531fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman
532fd2208d7c72ef5995b730f1e23b082261499e334Pierre Ossman	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
5337cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman		if (timeout == 0) {
534d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			printk(KERN_ERR "%s: Controller never released "
535acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman				"inhibit bit(s).\n", mmc_hostname(host->mmc));
536d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_dumpregs(host);
53717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman			cmd->error = -EIO;
538d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			tasklet_schedule(&host->finish_tasklet);
539d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			return;
540d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
5417cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman		timeout--;
5427cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman		mdelay(1);
5437cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman	}
544d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
545d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mod_timer(&host->timer, jiffies + 10 * HZ);
546d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
547d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->cmd = cmd;
548d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
549d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_prepare_data(host, cmd->data);
550d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
551d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
552d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
553c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman	sdhci_set_transfer_mode(host, cmd->data);
554c7fa9963ee6317b54e85b260791d603ea2feb8e3Pierre Ossman
555d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
556acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman		printk(KERN_ERR "%s: Unsupported response type!\n",
557d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			mmc_hostname(host->mmc));
55817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		cmd->error = -EINVAL;
559d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		tasklet_schedule(&host->finish_tasklet);
560d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return;
561d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
562d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
563d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!(cmd->flags & MMC_RSP_PRESENT))
564d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		flags = SDHCI_CMD_RESP_NONE;
565d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else if (cmd->flags & MMC_RSP_136)
566d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		flags = SDHCI_CMD_RESP_LONG;
567d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else if (cmd->flags & MMC_RSP_BUSY)
568d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		flags = SDHCI_CMD_RESP_SHORT_BUSY;
569d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else
570d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		flags = SDHCI_CMD_RESP_SHORT;
571d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
572d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (cmd->flags & MMC_RSP_CRC)
573d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		flags |= SDHCI_CMD_CRC;
574d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (cmd->flags & MMC_RSP_OPCODE)
575d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		flags |= SDHCI_CMD_INDEX;
576d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (cmd->data)
577d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		flags |= SDHCI_CMD_DATA;
578d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
579fb61e2895170920564410baadf71c5b3561dbf42Pierre Ossman	writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
580d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->ioaddr + SDHCI_COMMAND);
581d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
582d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
583d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_finish_command(struct sdhci_host *host)
584d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
585d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int i;
586d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
587d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	BUG_ON(host->cmd == NULL);
588d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
589d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->cmd->flags & MMC_RSP_PRESENT) {
590d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (host->cmd->flags & MMC_RSP_136) {
591d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			/* CRC is stripped so we need to do some shifting. */
592d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			for (i = 0;i < 4;i++) {
593d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				host->cmd->resp[i] = readl(host->ioaddr +
594d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman					SDHCI_RESPONSE + (3-i)*4) << 8;
595d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				if (i != 3)
596d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman					host->cmd->resp[i] |=
597d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman						readb(host->ioaddr +
598d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman						SDHCI_RESPONSE + (3-i)*4-1);
599d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			}
600d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		} else {
601d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
602d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
603d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
604d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
60517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	host->cmd->error = 0;
606d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
607e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman	if (host->data && host->data_early)
608e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman		sdhci_finish_data(host);
609e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman
610e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman	if (!host->cmd->data)
611d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		tasklet_schedule(&host->finish_tasklet);
612d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
613d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->cmd = NULL;
614d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
615d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
616d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
617d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
618d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int div;
619d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u16 clk;
6207cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman	unsigned long timeout;
621d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
622d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (clock == host->clock)
623d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return;
624d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
625d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
626d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
627d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (clock == 0)
628d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		goto out;
629d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
630d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	for (div = 1;div < 256;div *= 2) {
631d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if ((host->max_clk / div) <= clock)
632d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			break;
633d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
634d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	div >>= 1;
635d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
636d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	clk = div << SDHCI_DIVIDER_SHIFT;
637d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	clk |= SDHCI_CLOCK_INT_EN;
638d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
639d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
640d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/* Wait max 10 ms */
6417cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman	timeout = 10;
6427cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman	while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
6437cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman		& SDHCI_CLOCK_INT_STABLE)) {
6447cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman		if (timeout == 0) {
645acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman			printk(KERN_ERR "%s: Internal clock never "
646acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman				"stabilised.\n", mmc_hostname(host->mmc));
647d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_dumpregs(host);
648d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			return;
649d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
6507cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman		timeout--;
6517cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman		mdelay(1);
6527cb2c76fa2251474e42d55b75163c9d7ed11741ePierre Ossman	}
653d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
654d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	clk |= SDHCI_CLOCK_CARD_EN;
655d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
656d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
657d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout:
658d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->clock = clock;
659d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
660d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
661146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanstatic void sdhci_set_power(struct sdhci_host *host, unsigned short power)
662146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman{
663146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	u8 pwr;
664146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
665146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	if (host->power == power)
666146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		return;
667146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
6689e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	if (power == (unsigned short)-1) {
6699e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
670146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		goto out;
6719e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	}
6729e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt
6739e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	/*
6749e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	 * Spec says that we should clear the power reg before setting
6759e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	 * a new value. Some controllers don't seem to like this though.
6769e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	 */
6779e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
6789e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2Darren Salt		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
679146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
680146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	pwr = SDHCI_POWER_ON;
681146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
6824be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale	switch (1 << power) {
68355556da01284af8c2174b786b3eca8e11301b656Philip Langdale	case MMC_VDD_165_195:
684146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		pwr |= SDHCI_POWER_180;
685146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		break;
6864be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale	case MMC_VDD_29_30:
6874be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale	case MMC_VDD_30_31:
688146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		pwr |= SDHCI_POWER_300;
689146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		break;
6904be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale	case MMC_VDD_32_33:
6914be34c99a2f3aa90fa42e62c0918f07afb8a645bPhilip Langdale	case MMC_VDD_33_34:
692146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		pwr |= SDHCI_POWER_330;
693146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		break;
694146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	default:
695146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		BUG();
696146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	}
697146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
698146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
699146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
700146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossmanout:
701146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	host->power = power;
702146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman}
703146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
704d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
705d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
706d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * MMC callbacks                                                             *
707d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
708d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
709d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
710d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
711d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
712d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
713d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	unsigned long flags;
714d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
715d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = mmc_priv(mmc);
716d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
717d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock_irqsave(&host->lock, flags);
718d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
719d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	WARN_ON(host->mrq != NULL);
720d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
721d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_activate_led(host);
722d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
723d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->mrq = mrq;
724d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
725d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
72617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		host->mrq->cmd->error = -ENOMEDIUM;
727d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		tasklet_schedule(&host->finish_tasklet);
728d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	} else
729d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_send_command(host, mrq->cmd);
730d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
7315f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman	mmiowb();
732d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_unlock_irqrestore(&host->lock, flags);
733d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
734d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
735d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
736d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
737d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
738d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	unsigned long flags;
739d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u8 ctrl;
740d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
741d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = mmc_priv(mmc);
742d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
743d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock_irqsave(&host->lock, flags);
744d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
745d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
746d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Reset the chip on each power off.
747d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Should clear out any weird states.
748d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
749d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ios->power_mode == MMC_POWER_OFF) {
750d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
751d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_init(host);
752d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
753d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
754d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_set_clock(host, ios->clock);
755d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
756d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ios->power_mode == MMC_POWER_OFF)
757146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		sdhci_set_power(host, -1);
758d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else
759146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		sdhci_set_power(host, ios->vdd);
760d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
761d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
762cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman
763d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ios->bus_width == MMC_BUS_WIDTH_4)
764d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		ctrl |= SDHCI_CTRL_4BITBUS;
765d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else
766d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		ctrl &= ~SDHCI_CTRL_4BITBUS;
767cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman
768cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman	if (ios->timing == MMC_TIMING_SD_HS)
769cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman		ctrl |= SDHCI_CTRL_HISPD;
770cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman	else
771cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman		ctrl &= ~SDHCI_CTRL_HISPD;
772cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman
773d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
774d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
775b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	/*
776b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	 * Some (ENE) controllers go apeshit on some ios operation,
777b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	 * signalling timeout and CRC errors even on CMD0. Resetting
778b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	 * it on each ios seems to solve the problem.
779b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	 */
780b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo	if(host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
781b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo		sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
782b8352260d28b30cb2bb2df99814fb9c360e38901Leandro Dorileo
7835f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman	mmiowb();
784d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_unlock_irqrestore(&host->lock, flags);
785d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
786d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
787d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_get_ro(struct mmc_host *mmc)
788d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
789d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
790d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	unsigned long flags;
791d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int present;
792d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
793d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = mmc_priv(mmc);
794d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
795d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock_irqsave(&host->lock, flags);
796d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
797d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
798d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
799d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_unlock_irqrestore(&host->lock, flags);
800d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
801d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return !(present & SDHCI_WRITE_PROTECT);
802d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
803d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
804f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossmanstatic void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
805f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman{
806f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	struct sdhci_host *host;
807f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	unsigned long flags;
808f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	u32 ier;
809f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
810f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	host = mmc_priv(mmc);
811f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
812f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	spin_lock_irqsave(&host->lock, flags);
813f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
814f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
815f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
816f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	ier &= ~SDHCI_INT_CARD_INT;
817f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	if (enable)
818f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman		ier |= SDHCI_INT_CARD_INT;
819f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
820f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	writel(ier, host->ioaddr + SDHCI_INT_ENABLE);
821f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
822f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
823f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	mmiowb();
824f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
825f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	spin_unlock_irqrestore(&host->lock, flags);
826f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman}
827f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
828ab7aefd0b38297e6d2d71f43e8f81f9f4a36cdaeDavid Brownellstatic const struct mmc_host_ops sdhci_ops = {
829d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.request	= sdhci_request,
830d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.set_ios	= sdhci_set_ios,
831d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.get_ro		= sdhci_get_ro,
832f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	.enable_sdio_irq = sdhci_enable_sdio_irq,
833d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman};
834d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
835d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
836d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
837d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Tasklets                                                                  *
838d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
839d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
840d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
841d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_card(unsigned long param)
842d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
843d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
844d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	unsigned long flags;
845d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
846d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = (struct sdhci_host*)param;
847d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
848d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock_irqsave(&host->lock, flags);
849d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
850d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
851d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (host->mrq) {
852d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			printk(KERN_ERR "%s: Card removed during transfer!\n",
853d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				mmc_hostname(host->mmc));
854d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			printk(KERN_ERR "%s: Resetting controller.\n",
855d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				mmc_hostname(host->mmc));
856d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
857d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_reset(host, SDHCI_RESET_CMD);
858d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_reset(host, SDHCI_RESET_DATA);
859d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
86017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman			host->mrq->cmd->error = -ENOMEDIUM;
861d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			tasklet_schedule(&host->finish_tasklet);
862d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
863d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
864d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
865d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_unlock_irqrestore(&host->lock, flags);
866d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
867d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
868d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
869d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
870d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_tasklet_finish(unsigned long param)
871d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
872d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
873d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	unsigned long flags;
874d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct mmc_request *mrq;
875d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
876d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = (struct sdhci_host*)param;
877d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
878d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock_irqsave(&host->lock, flags);
879d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
880d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	del_timer(&host->timer);
881d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
882d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mrq = host->mrq;
883d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
884d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
885d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * The controller needs a reset of internal state machines
886d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * upon error conditions.
887d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
88817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (mrq->cmd->error ||
88917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		(mrq->data && (mrq->data->error ||
89017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		(mrq->data->stop && mrq->data->stop->error)))) {
891645289dca5021224279e67b4655796cafdfdad00Pierre Ossman
892645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		/* Some controllers need this kick or reset won't work here */
893645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
894645289dca5021224279e67b4655796cafdfdad00Pierre Ossman			unsigned int clock;
895645289dca5021224279e67b4655796cafdfdad00Pierre Ossman
896645289dca5021224279e67b4655796cafdfdad00Pierre Ossman			/* This is to force an update */
897645289dca5021224279e67b4655796cafdfdad00Pierre Ossman			clock = host->clock;
898645289dca5021224279e67b4655796cafdfdad00Pierre Ossman			host->clock = 0;
899645289dca5021224279e67b4655796cafdfdad00Pierre Ossman			sdhci_set_clock(host, clock);
900645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		}
901645289dca5021224279e67b4655796cafdfdad00Pierre Ossman
902645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		/* Spec says we should do both at the same time, but Ricoh
903645289dca5021224279e67b4655796cafdfdad00Pierre Ossman		   controllers do not like that. */
904d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_reset(host, SDHCI_RESET_CMD);
905d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_reset(host, SDHCI_RESET_DATA);
906d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
907d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
908d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->mrq = NULL;
909d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->cmd = NULL;
910d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->data = NULL;
911d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
912d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_deactivate_led(host);
913d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
9145f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman	mmiowb();
915d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_unlock_irqrestore(&host->lock, flags);
916d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
917d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc_request_done(host->mmc, mrq);
918d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
919d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
920d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_timeout_timer(unsigned long data)
921d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
922d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
923d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	unsigned long flags;
924d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
925d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = (struct sdhci_host*)data;
926d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
927d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock_irqsave(&host->lock, flags);
928d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
929d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->mrq) {
930acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman		printk(KERN_ERR "%s: Timeout waiting for hardware "
931acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman			"interrupt.\n", mmc_hostname(host->mmc));
932d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_dumpregs(host);
933d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
934d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (host->data) {
93517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman			host->data->error = -ETIMEDOUT;
936d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_finish_data(host);
937d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		} else {
938d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			if (host->cmd)
93917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman				host->cmd->error = -ETIMEDOUT;
940d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			else
94117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman				host->mrq->cmd->error = -ETIMEDOUT;
942d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
943d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			tasklet_schedule(&host->finish_tasklet);
944d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
945d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
946d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
9475f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman	mmiowb();
948d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_unlock_irqrestore(&host->lock, flags);
949d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
950d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
951d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
952d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
953d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Interrupt handling                                                        *
954d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
955d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
956d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
957d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
958d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
959d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	BUG_ON(intmask == 0);
960d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
961d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!host->cmd) {
962b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman		printk(KERN_ERR "%s: Got command interrupt 0x%08x even "
963b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman			"though no command operation was in progress.\n",
964b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman			mmc_hostname(host->mmc), (unsigned)intmask);
965d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_dumpregs(host);
966d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return;
967d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
968d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
96943b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman	if (intmask & SDHCI_INT_TIMEOUT)
97017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		host->cmd->error = -ETIMEDOUT;
97117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
97217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman			SDHCI_INT_INDEX))
97317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		host->cmd->error = -EILSEQ;
97443b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman
97517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (host->cmd->error)
976d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		tasklet_schedule(&host->finish_tasklet);
97743b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman	else if (intmask & SDHCI_INT_RESPONSE)
97843b58b36b7e6554b8a96be6b9f63542c583c06e5Pierre Ossman		sdhci_finish_command(host);
979d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
980d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
981d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
982d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
983d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	BUG_ON(intmask == 0);
984d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
985d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!host->data) {
986d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		/*
987d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		 * A data end interrupt is sent together with the response
988d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		 * for the stop command.
989d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		 */
990d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (intmask & SDHCI_INT_DATA_END)
991d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			return;
992d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
993b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman		printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
994b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman			"though no data operation was in progress.\n",
995b67ac3f339c76dfea3cc75fc0285b6d13edc35faPierre Ossman			mmc_hostname(host->mmc), (unsigned)intmask);
996d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_dumpregs(host);
997d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
998d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return;
999d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1000d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1001d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (intmask & SDHCI_INT_DATA_TIMEOUT)
100217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		host->data->error = -ETIMEDOUT;
100317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
100417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman		host->data->error = -EILSEQ;
1005d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
100617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman	if (host->data->error)
1007d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_finish_data(host);
1008d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else {
1009a406f5a3b68ee1db2306a2ba1c9b00dbd3505d05Pierre Ossman		if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
1010d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_transfer_pio(host);
1011d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
10126ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman		/*
10136ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman		 * We currently don't do anything fancy with DMA
10146ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman		 * boundaries, but as we can't disable the feature
10156ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman		 * we need to at least restart the transfer.
10166ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman		 */
10176ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman		if (intmask & SDHCI_INT_DMA_END)
10186ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman			writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
10196ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman				host->ioaddr + SDHCI_DMA_ADDRESS);
10206ba736a10e4ae63b38ccfee9f22b3263a6e5d050Pierre Ossman
1021e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman		if (intmask & SDHCI_INT_DATA_END) {
1022e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman			if (host->cmd) {
1023e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman				/*
1024e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman				 * Data managed to finish before the
1025e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman				 * command completed. Make sure we do
1026e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman				 * things in the proper order.
1027e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman				 */
1028e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman				host->data_early = 1;
1029e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman			} else {
1030e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman				sdhci_finish_data(host);
1031e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman			}
1032e538fbe83e374a3521128c1f4642aca037661c9dPierre Ossman		}
1033d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1034d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1035d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
10367d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t sdhci_irq(int irq, void *dev_id)
1037d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1038d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	irqreturn_t result;
1039d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host* host = dev_id;
1040d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u32 intmask;
1041f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	int cardint = 0;
1042d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1043d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock(&host->lock);
1044d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1045d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
1046d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
104762df67a523acd7a22d936bf946b1889dbd60ca98Mark Lord	if (!intmask || intmask == 0xffffffff) {
1048d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		result = IRQ_NONE;
1049d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		goto out;
1050d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1051d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1052d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
1053d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
10543192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
10553192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
10563192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman			host->ioaddr + SDHCI_INT_STATUS);
1057d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		tasklet_schedule(&host->card_tasklet);
10583192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman	}
1059d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
10603192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman	intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
1061d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
10623192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman	if (intmask & SDHCI_INT_CMD_MASK) {
1063d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		writel(intmask & SDHCI_INT_CMD_MASK,
1064d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			host->ioaddr + SDHCI_INT_STATUS);
10653192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
1066d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1067d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1068d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (intmask & SDHCI_INT_DATA_MASK) {
1069d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		writel(intmask & SDHCI_INT_DATA_MASK,
1070d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			host->ioaddr + SDHCI_INT_STATUS);
10713192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
1072d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1073d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1074d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
1075d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1076964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman	intmask &= ~SDHCI_INT_ERROR;
1077964f9ce2ff42dc47cf40fbd2f5c81cd60689e384Pierre Ossman
1078d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (intmask & SDHCI_INT_BUS_POWER) {
10793192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		printk(KERN_ERR "%s: Card is consuming too much power!\n",
1080d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			mmc_hostname(host->mmc));
10813192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman		writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
1082d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1083d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
10849d26a5d3f2b9c4fe4b2ba491683c6989ecd6ae04Rolf Eike Beer	intmask &= ~SDHCI_INT_BUS_POWER;
10853192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman
1086f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	if (intmask & SDHCI_INT_CARD_INT)
1087f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman		cardint = 1;
1088f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
1089f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	intmask &= ~SDHCI_INT_CARD_INT;
1090f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
10913192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman	if (intmask) {
1092acf1da4522add3771f4851c09c7fe6bcf1dd6636Pierre Ossman		printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
10933192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman			mmc_hostname(host->mmc), intmask);
1094d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_dumpregs(host);
1095d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1096d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
10973192a28f7d34ea8f1d0fef8ca5bc0314b5b5bb19Pierre Ossman	}
1098d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1099d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	result = IRQ_HANDLED;
1100d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
11015f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman	mmiowb();
1102d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanout:
1103d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_unlock(&host->lock);
1104d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1105f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	/*
1106f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	 * We have to delay this as it calls back into the driver.
1107f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	 */
1108f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	if (cardint)
1109f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman		mmc_signal_sdio_irq(host->mmc);
1110f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman
1111d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return result;
1112d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1113d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1114d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
1115d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
1116d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Suspend/resume                                                            *
1117d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
1118d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
1119d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1120d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_PM
1121d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1122d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
1123d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1124d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_chip *chip;
1125d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int i, ret;
1126d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1127d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip = pci_get_drvdata(pdev);
1128d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!chip)
1129d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return 0;
1130d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1131d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	DBG("Suspending...\n");
1132d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1133d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	for (i = 0;i < chip->num_slots;i++) {
1134d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (!chip->hosts[i])
1135d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			continue;
1136d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
1137d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (ret) {
1138d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			for (i--;i >= 0;i--)
1139d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				mmc_resume_host(chip->hosts[i]->mmc);
1140d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			return ret;
1141d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
1142d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1143d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1144d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_save_state(pdev);
1145d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
1146a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman
1147a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman	for (i = 0;i < chip->num_slots;i++) {
1148a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman		if (!chip->hosts[i])
1149a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman			continue;
1150a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman		free_irq(chip->hosts[i]->irq, chip->hosts[i]);
1151a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman	}
1152a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman
1153d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_disable_device(pdev);
1154d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_set_power_state(pdev, pci_choose_state(pdev, state));
1155d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1156d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return 0;
1157d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1158d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1159d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int sdhci_resume (struct pci_dev *pdev)
1160d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1161d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_chip *chip;
1162d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int i, ret;
1163d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1164d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip = pci_get_drvdata(pdev);
1165d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!chip)
1166d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return 0;
1167d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1168d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	DBG("Resuming...\n");
1169d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1170d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_set_power_state(pdev, PCI_D0);
1171d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_restore_state(pdev);
1172df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman	ret = pci_enable_device(pdev);
1173df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman	if (ret)
1174df1c4b7bf7f3b3a48d78c6e5c2fc5b9a1c01b821Pierre Ossman		return ret;
1175d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1176d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	for (i = 0;i < chip->num_slots;i++) {
1177d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (!chip->hosts[i])
1178d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			continue;
1179d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
1180d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			pci_set_master(pdev);
1181a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman		ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
1182a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman			IRQF_SHARED, chip->hosts[i]->slot_descr,
1183a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman			chip->hosts[i]);
1184a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman		if (ret)
1185a715dfc7b9ef15ed5b398b185bd84cc015ff37f6Pierre Ossman			return ret;
1186d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_init(chip->hosts[i]);
11875f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman		mmiowb();
1188d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		ret = mmc_resume_host(chip->hosts[i]->mmc);
1189d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (ret)
1190d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			return ret;
1191d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1192d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1193d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return 0;
1194d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1195d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1196d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#else /* CONFIG_PM */
1197d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1198d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define sdhci_suspend NULL
1199d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#define sdhci_resume NULL
1200d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1201d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif /* CONFIG_PM */
1202d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1203d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
1204d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
1205d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Device probing/removal                                                    *
1206d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
1207d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
1208d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1209d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
1210d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1211d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int ret;
12124a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman	unsigned int version;
1213d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_chip *chip;
1214d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct mmc_host *mmc;
1215d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
1216d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1217d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	u8 first_bar;
1218d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	unsigned int caps;
1219d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1220d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip = pci_get_drvdata(pdev);
1221d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	BUG_ON(!chip);
1222d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1223d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
1224d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ret)
1225d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return ret;
1226d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1227d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
1228d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1229d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (first_bar > 5) {
1230d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
1231d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return -ENODEV;
1232d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1233d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1234d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
1235d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
1236d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return -ENODEV;
1237d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1238d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1239d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
1240a98087cf81e91999a91ceedb2d2e3a95827c651fPierre Ossman		printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
1241a98087cf81e91999a91ceedb2d2e3a95827c651fPierre Ossman			"You may experience problems.\n");
1242d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1243d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
12446743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman	if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
12456743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman		printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
12466743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman		return -ENODEV;
12476743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman	}
12486743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman
12496743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman	if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
12506743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman		printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
12516743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman		return -ENODEV;
12526743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman	}
12536743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman
1254d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
1255d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!mmc)
1256d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return -ENOMEM;
1257d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1258d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = mmc_priv(mmc);
1259d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->mmc = mmc;
1260d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
12618a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman	host->chip = chip;
12628a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman	chip->hosts[slot] = host;
12638a4da1430f7f2a16df3be9c7b5d55ba4e75b708cPierre Ossman
1264d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->bar = first_bar + slot;
1265d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1266d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->addr = pci_resource_start(pdev, host->bar);
1267d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->irq = pdev->irq;
1268d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1269d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
1270d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1271d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
1272d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1273d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ret = pci_request_region(pdev, host->bar, host->slot_descr);
1274d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ret)
1275d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		goto free;
1276d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1277d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->ioaddr = ioremap_nocache(host->addr,
1278d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		pci_resource_len(pdev, host->bar));
1279d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!host->ioaddr) {
1280d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		ret = -ENOMEM;
1281d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		goto release;
1282d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1283d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1284d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman	sdhci_reset(host, SDHCI_RESET_ALL);
1285d96649ed5ace812ffc8d86252d7c663326ca47f8Pierre Ossman
12864a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman	version = readw(host->ioaddr + SDHCI_HOST_VERSION);
12874a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman	version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
12884a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman	if (version != 0) {
12894a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman		printk(KERN_ERR "%s: Unknown controller version (%d). "
12908b1b21853bab15fe5b60b8222786fe036c4dc365Pierre Ossman			"You may experience problems.\n", host->slot_descr,
12914a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman			version);
12924a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman	}
12934a9655051fb1efa568e53baf5dfb21e33bad6bf6Pierre Ossman
1294d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
1295d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1296d6f8deecefc133cac044f6029bdb349a1cb8753aPierre Ossman	if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
129798608076a21914ab12f1c858a0cdf55366260f12Pierre Ossman		host->flags |= SDHCI_USE_DMA;
12986743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman	else if (!(caps & SDHCI_CAN_DO_DMA))
12996743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman		DBG("Controller doesn't have DMA capability\n");
13006743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman	else
1301d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->flags |= SDHCI_USE_DMA;
1302d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
13037c168e3db7d900008ee304574057e0dc1a8505afFeng Tang	if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
13047c168e3db7d900008ee304574057e0dc1a8505afFeng Tang		(host->flags & SDHCI_USE_DMA)) {
13057c168e3db7d900008ee304574057e0dc1a8505afFeng Tang		DBG("Disabling DMA as it is marked broken");
13067c168e3db7d900008ee304574057e0dc1a8505afFeng Tang		host->flags &= ~SDHCI_USE_DMA;
13077c168e3db7d900008ee304574057e0dc1a8505afFeng Tang	}
13087c168e3db7d900008ee304574057e0dc1a8505afFeng Tang
130956e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang	if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
131056e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang		(host->flags & SDHCI_USE_DMA)) {
131156e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang		printk(KERN_WARNING "%s: Will use DMA "
131256e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang			"mode even though HW doesn't fully "
131356e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang			"claim to support it.\n", host->slot_descr);
131456e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang	}
131556e71efe44eb06ae1761f43cca70a5f3cc54c0fbFeng Tang
1316d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->flags & SDHCI_USE_DMA) {
1317d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
1318d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			printk(KERN_WARNING "%s: No suitable DMA available. "
1319d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				"Falling back to PIO.\n", host->slot_descr);
1320d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			host->flags &= ~SDHCI_USE_DMA;
1321d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
1322d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1323d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1324d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->flags & SDHCI_USE_DMA)
1325d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		pci_set_master(pdev);
1326d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else /* XXX: Hack to get MMC layer to avoid highmem */
1327d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		pdev->dma_mask = 0;
1328d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
13298ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman	host->max_clk =
13308ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
13318ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman	if (host->max_clk == 0) {
13328ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman		printk(KERN_ERR "%s: Hardware doesn't specify base clock "
13338ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman			"frequency.\n", host->slot_descr);
13348ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman		ret = -ENODEV;
13358ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman		goto unmap;
13368ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman	}
1337d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host->max_clk *= 1000000;
1338d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
13391c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	host->timeout_clk =
13401c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
13411c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	if (host->timeout_clk == 0) {
13421c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
13431c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman			"frequency.\n", host->slot_descr);
13441c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		ret = -ENODEV;
13451c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		goto unmap;
13461c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	}
13471c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
13481c8cde92fa5c57daa9ff58d970ca6374f8d484a2Pierre Ossman		host->timeout_clk *= 1000;
1349d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1350d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
1351d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Set host parameters.
1352d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
1353d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc->ops = &sdhci_ops;
1354d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc->f_min = host->max_clk / 256;
1355d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc->f_max = host->max_clk;
1356f75979b77fb20b01522d8fab96dfc76cc9f42420Pierre Ossman	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ;
1357d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1358cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman	if (caps & SDHCI_CAN_DO_HISPD)
1359cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
1360cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman
1361146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	mmc->ocr_avail = 0;
1362146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	if (caps & SDHCI_CAN_VDD_330)
1363146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
1364c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman	if (caps & SDHCI_CAN_VDD_300)
1365146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
1366c70840e819acdbab96b8cdf71d27cb68c6567efaPierre Ossman	if (caps & SDHCI_CAN_VDD_180)
136755556da01284af8c2174b786b3eca8e11301b656Philip Langdale		mmc->ocr_avail |= MMC_VDD_165_195;
1368146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
1369146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	if (mmc->ocr_avail == 0) {
1370146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		printk(KERN_ERR "%s: Hardware doesn't report any "
1371146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman			"support voltages.\n", host->slot_descr);
1372146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		ret = -ENODEV;
1373146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman		goto unmap;
1374146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman	}
1375146ad66eac836c0b976c98f428d73e1f6a75270dPierre Ossman
1376d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	spin_lock_init(&host->lock);
1377d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1378d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
1379d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Maximum number of segments. Hardware cannot do scatter lists.
1380d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
1381d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (host->flags & SDHCI_USE_DMA)
1382d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		mmc->max_hw_segs = 1;
1383d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	else
1384d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		mmc->max_hw_segs = 16;
1385d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc->max_phys_segs = 16;
1386d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1387d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
1388bab7696184bbf0ea48d56902bd1f9ac983079ad2Pierre Ossman	 * Maximum number of sectors in one transfer. Limited by DMA boundary
138955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 * size (512KiB).
1390d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
139155db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	mmc->max_req_size = 524288;
1392d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1393d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
1394d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Maximum segment size. Could be one segment with the maximum number
139555db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 * of bytes.
1396d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
139755db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	mmc->max_seg_size = mmc->max_req_size;
1398d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1399d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	/*
1400fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	 * Maximum block size. This varies from controller to controller and
1401fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	 * is specified in the capabilities register.
1402fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	 */
1403fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
1404fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	if (mmc->max_blk_size >= 3) {
140503f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel		printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n",
1406fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman			host->slot_descr);
140703f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel		mmc->max_blk_size = 512;
140803f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel	} else
140903f8590d90844f04d20488a80e75eaf4c4e0b35cDavid Vrabel		mmc->max_blk_size = 512 << mmc->max_blk_size;
1410fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman
1411fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman	/*
141255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 * Maximum block count.
141355db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	 */
141455db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	mmc->max_blk_count = 65535;
141555db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman
141655db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman	/*
1417d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 * Init tasklets.
1418d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	 */
1419d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	tasklet_init(&host->card_tasklet,
1420d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_tasklet_card, (unsigned long)host);
1421d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	tasklet_init(&host->finish_tasklet,
1422d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sdhci_tasklet_finish, (unsigned long)host);
1423d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1424e4cad1b5a4851c90c1bcf460062074a2fa10815bAl Viro	setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
1425d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1426dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner	ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
1427d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->slot_descr, host);
1428d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ret)
14298ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossman		goto untasklet;
1430d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1431d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_init(host);
1432d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1433d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#ifdef CONFIG_MMC_DEBUG
1434d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_dumpregs(host);
1435d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman#endif
1436d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
14375f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman	mmiowb();
14385f25a66f6bbac563c94af94f03491b3ae43c40afPierre Ossman
1439d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc_add_host(mmc);
1440d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1441d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
1442d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		host->addr, host->irq,
1443d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
1444d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1445d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return 0;
1446d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
14478ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossmanuntasklet:
1448d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	tasklet_kill(&host->card_tasklet);
1449d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	tasklet_kill(&host->finish_tasklet);
14508ef1a14379e105c1419d21e96ffac53202bc0501Pierre Ossmanunmap:
1451d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	iounmap(host->ioaddr);
1452d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanrelease:
1453d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_release_region(pdev, host->bar);
1454d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanfree:
1455d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc_free_host(mmc);
1456d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1457d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return ret;
1458d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1459d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1460d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void sdhci_remove_slot(struct pci_dev *pdev, int slot)
1461d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1462d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_chip *chip;
1463d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct mmc_host *mmc;
1464d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_host *host;
1465d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1466d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip = pci_get_drvdata(pdev);
1467d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	host = chip->hosts[slot];
1468d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc = host->mmc;
1469d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1470d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip->hosts[slot] = NULL;
1471d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1472d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc_remove_host(mmc);
1473d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1474d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	sdhci_reset(host, SDHCI_RESET_ALL);
1475d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1476d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	free_irq(host->irq, host);
1477d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1478d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	del_timer_sync(&host->timer);
1479d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1480d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	tasklet_kill(&host->card_tasklet);
1481d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	tasklet_kill(&host->finish_tasklet);
1482d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1483d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	iounmap(host->ioaddr);
1484d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1485d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_release_region(pdev, host->bar);
1486d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1487d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	mmc_free_host(mmc);
1488d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1489d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1490d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __devinit sdhci_probe(struct pci_dev *pdev,
1491d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	const struct pci_device_id *ent)
1492d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1493d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int ret, i;
149451f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman	u8 slots, rev;
1495d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_chip *chip;
1496d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1497d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	BUG_ON(pdev == NULL);
1498d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	BUG_ON(ent == NULL);
1499d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
150051f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
150151f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman
150251f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman	printk(KERN_INFO DRIVER_NAME
150351f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman		": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
150451f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
150551f82bc07a9673d790c2a17de8e3fa8046543f04Pierre Ossman		(int)rev);
1506d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1507d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
1508d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ret)
1509d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return ret;
1510d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1511d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
1512d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	DBG("found %d slot(s)\n", slots);
1513d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (slots == 0)
1514d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return -ENODEV;
1515d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1516d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	ret = pci_enable_device(pdev);
1517d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (ret)
1518d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		return ret;
1519d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1520d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip = kzalloc(sizeof(struct sdhci_chip) +
1521d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
1522d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (!chip) {
1523d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		ret = -ENOMEM;
1524d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		goto err;
1525d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1526d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1527d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip->pdev = pdev;
1528df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman	chip->quirks = ent->driver_data;
1529df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman
1530df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman	if (debug_quirks)
1531df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossman		chip->quirks = debug_quirks;
1532d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1533d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip->num_slots = slots;
1534d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_set_drvdata(pdev, chip);
1535d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1536d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	for (i = 0;i < slots;i++) {
1537d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		ret = sdhci_probe_slot(pdev, i);
1538d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		if (ret) {
1539d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			for (i--;i >= 0;i--)
1540d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman				sdhci_remove_slot(pdev, i);
1541d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			goto free;
1542d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		}
1543d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1544d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1545d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return 0;
1546d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1547d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanfree:
1548d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_set_drvdata(pdev, NULL);
1549d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	kfree(chip);
1550d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1551d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanerr:
1552d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_disable_device(pdev);
1553d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return ret;
1554d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1555d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1556d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void __devexit sdhci_remove(struct pci_dev *pdev)
1557d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1558d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	int i;
1559d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	struct sdhci_chip *chip;
1560d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1561d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	chip = pci_get_drvdata(pdev);
1562d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1563d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	if (chip) {
1564d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		for (i = 0;i < chip->num_slots;i++)
1565d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman			sdhci_remove_slot(pdev, i);
1566d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1567d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		pci_set_drvdata(pdev, NULL);
1568d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1569d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman		kfree(chip);
1570d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	}
1571d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1572d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_disable_device(pdev);
1573d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1574d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1575d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic struct pci_driver sdhci_driver = {
1576d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.name = 	DRIVER_NAME,
1577d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.id_table =	pci_ids,
1578d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.probe = 	sdhci_probe,
1579d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.remove =	__devexit_p(sdhci_remove),
1580d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.suspend =	sdhci_suspend,
1581d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	.resume	=	sdhci_resume,
1582d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman};
1583d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1584d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman/*****************************************************************************\
1585d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
1586d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman * Driver init/exit                                                          *
1587d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman *                                                                           *
1588d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman\*****************************************************************************/
1589d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1590d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic int __init sdhci_drv_init(void)
1591d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1592d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_INFO DRIVER_NAME
159352fbf9c976b36654e08e94c3107ddbaac7e2da33Pierre Ossman		": Secure Digital Host Controller Interface driver\n");
1594d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
1595d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1596d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	return pci_register_driver(&sdhci_driver);
1597d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1598d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1599d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanstatic void __exit sdhci_drv_exit(void)
1600d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman{
1601d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	DBG("Exiting\n");
1602d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1603d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman	pci_unregister_driver(&sdhci_driver);
1604d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman}
1605d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1606d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_init(sdhci_drv_init);
1607d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossmanmodule_exit(sdhci_drv_exit);
1608d129bceb1d44ed3c23b99164849193703372bab4Pierre Ossman
1609df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre Ossmanmodule_param(debug_quirks, uint, 0444);
16106743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman
1611d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
1612d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
1613d129bceb1d44ed3c23b99164849193703372bab4Pierre OssmanMODULE_LICENSE("GPL");
16146743527441430586aa82a0dee1b2700a2a974ebcPierre Ossman
1615df673b227ce08a7706b30fd2bf6512393d9c3c29Pierre OssmanMODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
1616