Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 102157
b: refs/heads/master
c: 4489428
h: refs/heads/master
i:
  102155: dac69b1
v: v3
  • Loading branch information
Pierre Ossman committed Jul 15, 2008
1 parent 736230a commit 5872978
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 45211e21598441a32e53cf5032b7faeac143df6d
refs/heads/master: 4489428ab5a49a6f443d9aa17f1d891417787d7b
127 changes: 125 additions & 2 deletions trunk/drivers/mmc/host/sdhci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@
#define MAX_SLOTS 8

struct sdhci_pci_chip;
struct sdhci_pci_slot;

struct sdhci_pci_fixes {
unsigned int quirks;

int (*probe)(struct sdhci_pci_chip*);

int (*probe_slot)(struct sdhci_pci_slot*);
void (*remove_slot)(struct sdhci_pci_slot*);

int (*suspend)(struct sdhci_pci_chip*,
pm_message_t);
int (*resume)(struct sdhci_pci_chip*);
};

Expand Down Expand Up @@ -132,6 +138,38 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
{
int ret;

/*
* JMicron chips can have two interfaces to the same hardware
* in order to work around limitations in Microsoft's driver.
* We need to make sure we only bind to one of them.
*
* This code assumes two things:
*
* 1. The PCI code adds subfunctions in order.
*
* 2. The MMC interface has a lower subfunction number
* than the SD interface.
*/
if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) {
struct pci_dev *sd_dev;

sd_dev = NULL;
while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON,
PCI_DEVICE_ID_JMICRON_JMB38X_MMC, sd_dev)) != NULL) {
if ((PCI_SLOT(chip->pdev->devfn) ==
PCI_SLOT(sd_dev->devfn)) &&
(chip->pdev->bus == sd_dev->bus))
break;
}

if (sd_dev) {
pci_dev_put(sd_dev);
dev_info(&chip->pdev->dev, "Refusing to bind to "
"secondary interface.\n");
return -ENODEV;
}
}

/*
* JMicron chips need a bit of a nudge to enable the power
* output pins.
Expand All @@ -145,9 +183,58 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
return 0;
}

static void jmicron_enable_mmc(struct sdhci_host *host, int on)
{
u8 scratch;

scratch = readb(host->ioaddr + 0xC0);

if (on)
scratch |= 0x01;
else
scratch &= ~0x01;

writeb(scratch, host->ioaddr + 0xC0);
}

static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
{
/*
* The secondary interface requires a bit set to get the
* interrupts.
*/
if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC)
jmicron_enable_mmc(slot->host, 1);

return 0;
}

static void jmicron_remove_slot(struct sdhci_pci_slot *slot)
{
if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC)
jmicron_enable_mmc(slot->host, 0);
}

static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state)
{
int i;

if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) {
for (i = 0;i < chip->num_slots;i++)
jmicron_enable_mmc(chip->slots[i]->host, 0);
}

return 0;
}

static int jmicron_resume(struct sdhci_pci_chip *chip)
{
int ret;
int ret, i;

if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) {
for (i = 0;i < chip->num_slots;i++)
jmicron_enable_mmc(chip->slots[i]->host, 1);
}

ret = jmicron_pmos(chip, 1);
if (ret) {
Expand All @@ -165,6 +252,10 @@ static const struct sdhci_pci_fixes sdhci_jmicron = {

.probe = jmicron_probe,

.probe_slot = jmicron_probe_slot,
.remove_slot = jmicron_remove_slot,

.suspend = jmicron_suspend,
.resume = jmicron_resume,
};

Expand Down Expand Up @@ -225,6 +316,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = (kernel_ulong_t)&sdhci_jmicron,
},

{
.vendor = PCI_VENDOR_ID_JMICRON,
.device = PCI_DEVICE_ID_JMICRON_JMB38X_MMC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_jmicron,
},

{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
Expand Down Expand Up @@ -301,6 +400,15 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
}
}

if (chip->fixes && chip->fixes->suspend) {
ret = chip->fixes->suspend(chip, state);
if (ret) {
for (i = chip->num_slots - 1;i >= 0;i--)
sdhci_resume_host(chip->slots[i]->host);
return ret;
}
}

pci_save_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
pci_disable_device(pdev);
Expand Down Expand Up @@ -418,12 +526,22 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
goto release;
}

if (chip->fixes && chip->fixes->probe_slot) {
ret = chip->fixes->probe_slot(slot);
if (ret)
goto unmap;
}

ret = sdhci_add_host(host);
if (ret)
goto unmap;
goto remove;

return slot;

remove:
if (chip->fixes && chip->fixes->remove_slot)
chip->fixes->remove_slot(slot);

unmap:
iounmap(host->ioaddr);

Expand All @@ -437,7 +555,12 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
{
sdhci_remove_host(slot->host);

if (slot->chip->fixes && slot->chip->fixes->remove_slot)
slot->chip->fixes->remove_slot(slot);

pci_release_region(slot->chip->pdev, slot->pci_bar);

sdhci_free_host(slot->host);
}

Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/pci_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -2188,6 +2188,7 @@
#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381
#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382
#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383

#define PCI_VENDOR_ID_KORENIX 0x1982
Expand Down

0 comments on commit 5872978

Please sign in to comment.