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