GIT 52c260bfe47c7e3b6a2e27723b95040338fdca04 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc.git#for-andrew 52c260bfe47c7e3b6a2e27723b95040338fdca04 commit 52c260bfe47c7e3b6a2e27723b95040338fdca04 Author: Pierre Ossman Date: Fri Mar 21 23:52:39 2008 +0100 mmc: use sysfs groups to handle conditional attributes Suppressing uevents turned out to be a bad idea as it screws up the order of events, making user space very confused. Change the system to use sysfs groups instead. Signed-off-by: Pierre Ossman commit 7ecb4d485a3ddbb13de9c1232d230f3db8114541 Author: Pierre Ossman Date: Mon Mar 17 10:29:38 2008 +0100 sdhci: allow led to be controlled freely Hook up the controller LED to the LED subsystem, allowing more flexible control than simply indicating an ongoing request. Signed-off-by: Pierre Ossman commit 833f22195e8811495cff117bcd178888f259e312 Author: Pierre Ossman Date: Sat Mar 8 23:44:25 2008 +0100 sdhci: remove custom controller name Remove the use of the sdhci specific device name and use the mmc controller name instead. Signed-off-by: Pierre Ossman commit 99bfbc09578dc10938af3a53a44055829e00d263 Author: Pierre Ossman Date: Sat Mar 8 23:43:19 2008 +0100 mmc: set controller name early Reorganise code so that mmc_hostname() works directly after allocation. That way host drivers can use that name for resource allocations and messages during probing. Signed-off-by: Pierre Ossman drivers/mmc/core/host.c | 39 +++++++++++--------- drivers/mmc/host/sdhci.c | 88 +++++++++++++++++++++++++++++++-------------- drivers/mmc/host/sdhci.h | 9 +++-- 3 files changed, 87 insertions(+), 49 deletions(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index c65d203..1d795c5 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -2,7 +2,7 @@ * linux/drivers/mmc/core/host.c * * Copyright (C) 2003 Russell King, All Rights Reserved. - * Copyright (C) 2007 Pierre Ossman + * Copyright (C) 2007-2008 Pierre Ossman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -57,12 +57,25 @@ static DEFINE_SPINLOCK(mmc_host_lock); */ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) { + int err; struct mmc_host *host; + if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) + return NULL; + host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); if (!host) return NULL; + spin_lock(&mmc_host_lock); + err = idr_get_new(&mmc_host_idr, host, &host->index); + spin_unlock(&mmc_host_lock); + if (err) + goto free; + + snprintf(host->class_dev.bus_id, BUS_ID_SIZE, + "mmc%d", host->index); + host->parent = dev; host->class_dev.parent = dev; host->class_dev.class = &mmc_host_class; @@ -85,6 +98,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_count = PAGE_CACHE_SIZE / 512; return host; + +free: + kfree(host); + return NULL; } EXPORT_SYMBOL(mmc_alloc_host); @@ -104,18 +121,6 @@ int mmc_add_host(struct mmc_host *host) WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && !host->ops->enable_sdio_irq); - if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) - return -ENOMEM; - - spin_lock(&mmc_host_lock); - err = idr_get_new(&mmc_host_idr, host, &host->index); - spin_unlock(&mmc_host_lock); - if (err) - return err; - - snprintf(host->class_dev.bus_id, BUS_ID_SIZE, - "mmc%d", host->index); - led_trigger_register_simple(host->class_dev.bus_id, &host->led); err = device_add(&host->class_dev); @@ -144,10 +149,6 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); led_trigger_unregister_simple(host->led); - - spin_lock(&mmc_host_lock); - idr_remove(&mmc_host_idr, host->index); - spin_unlock(&mmc_host_lock); } EXPORT_SYMBOL(mmc_remove_host); @@ -160,6 +161,10 @@ EXPORT_SYMBOL(mmc_remove_host); */ void mmc_free_host(struct mmc_host *host) { + spin_lock(&mmc_host_lock); + idr_remove(&mmc_host_idr, host->index); + spin_unlock(&mmc_host_lock); + put_device(&host->class_dev); } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4b673aa..6250eb5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,8 @@ #include #include +#include + #include #include "sdhci.h" @@ -30,10 +32,6 @@ static unsigned int debug_quirks = 0; -/* For multi controllers in one platform case */ -static u16 chip_index = 0; -static spinlock_t index_lock; - /* * Different quirks to handle when the hardware deviates from a strict * interpretation of the SDHCI specification. @@ -256,6 +254,24 @@ static void sdhci_deactivate_led(struct sdhci_host *host) writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); } +#ifdef CONFIG_LEDS_CLASS +static void sdhci_led_control(struct led_classdev *led, + enum led_brightness brightness) +{ + struct sdhci_host *host = container_of(led, struct sdhci_host, led); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (brightness == LED_OFF) + sdhci_deactivate_led(host); + else + sdhci_activate_led(host); + + spin_unlock_irqrestore(&host->lock, flags); +} +#endif + /*****************************************************************************\ * * * Core functions * @@ -773,7 +789,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); +#ifndef CONFIG_LEDS_CLASS sdhci_activate_led(host); +#endif host->mrq = mrq; @@ -965,7 +983,9 @@ static void sdhci_tasklet_finish(unsigned long param) host->cmd = NULL; host->data = NULL; +#ifndef CONFIG_LEDS_CLASS sdhci_deactivate_led(host); +#endif mmiowb(); spin_unlock_irqrestore(&host->lock, flags); @@ -1105,7 +1125,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) goto out; } - DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask); + DBG("*** %s got interrupt: 0x%08x\n", + mmc_hostname(host->mmc), intmask); if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), @@ -1235,7 +1256,7 @@ static int sdhci_resume (struct pci_dev *pdev) if (chip->hosts[i]->flags & SDHCI_USE_DMA) pci_set_master(pdev); ret = request_irq(chip->hosts[i]->irq, sdhci_irq, - IRQF_SHARED, chip->hosts[i]->slot_descr, + IRQF_SHARED, mmc_hostname(chip->hosts[i]->mmc), chip->hosts[i]); if (ret) return ret; @@ -1324,9 +1345,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq); - snprintf(host->slot_descr, 20, "sdhc%d:slot%d", chip->index, slot); - - ret = pci_request_region(pdev, host->bar, host->slot_descr); + ret = pci_request_region(pdev, host->bar, mmc_hostname(mmc)); if (ret) goto free; @@ -1343,7 +1362,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; if (version > 1) { printk(KERN_ERR "%s: Unknown controller version (%d). " - "You may experience problems.\n", host->slot_descr, + "You may experience problems.\n", mmc_hostname(mmc), version); } @@ -1366,13 +1385,13 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) (host->flags & SDHCI_USE_DMA)) { printk(KERN_WARNING "%s: Will use DMA " "mode even though HW doesn't fully " - "claim to support it.\n", host->slot_descr); + "claim to support it.\n", mmc_hostname(mmc)); } if (host->flags & SDHCI_USE_DMA) { if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "%s: No suitable DMA available. " - "Falling back to PIO.\n", host->slot_descr); + "Falling back to PIO.\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_DMA; } } @@ -1386,7 +1405,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; if (host->max_clk == 0) { printk(KERN_ERR "%s: Hardware doesn't specify base clock " - "frequency.\n", host->slot_descr); + "frequency.\n", mmc_hostname(mmc)); ret = -ENODEV; goto unmap; } @@ -1396,7 +1415,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; if (host->timeout_clk == 0) { printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " - "frequency.\n", host->slot_descr); + "frequency.\n", mmc_hostname(mmc)); ret = -ENODEV; goto unmap; } @@ -1424,7 +1443,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) if (mmc->ocr_avail == 0) { printk(KERN_ERR "%s: Hardware doesn't report any " - "support voltages.\n", host->slot_descr); + "support voltages.\n", mmc_hostname(mmc)); ret = -ENODEV; goto unmap; } @@ -1458,8 +1477,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) */ mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; if (mmc->max_blk_size >= 3) { - printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n", - host->slot_descr); + printk(KERN_WARNING "%s: Invalid maximum block size, " + "assuming 512 bytes\n", mmc_hostname(mmc)); mmc->max_blk_size = 512; } else mmc->max_blk_size = 512 << mmc->max_blk_size; @@ -1480,7 +1499,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, - host->slot_descr, host); + mmc_hostname(mmc), host); if (ret) goto untasklet; @@ -1490,16 +1509,32 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) sdhci_dumpregs(host); #endif +#ifdef CONFIG_LEDS_CLASS + host->led.name = mmc_hostname(mmc); + host->led.brightness = LED_OFF; + host->led.default_trigger = mmc_hostname(mmc); + host->led.brightness_set = sdhci_led_control; + + ret = led_classdev_register(&pdev->dev, &host->led); + if (ret) + goto reset; +#endif + mmiowb(); mmc_add_host(mmc); - printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc), - host->addr, host->irq, + printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", + mmc_hostname(mmc), host->addr, host->irq, (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); return 0; +#ifdef CONFIG_LEDS_CLASS +reset: + sdhci_reset(host, SDHCI_RESET_ALL); + free_irq(host->irq, host); +#endif untasklet: tasklet_kill(&host->card_tasklet); tasklet_kill(&host->finish_tasklet); @@ -1527,6 +1562,10 @@ static void sdhci_remove_slot(struct pci_dev *pdev, int slot) mmc_remove_host(mmc); +#ifdef CONFIG_LEDS_CLASS + led_classdev_unregister(&host->led); +#endif + sdhci_reset(host, SDHCI_RESET_ALL); free_irq(host->irq, host); @@ -1589,11 +1628,6 @@ static int __devinit sdhci_probe(struct pci_dev *pdev, chip->num_slots = slots; pci_set_drvdata(pdev, chip); - /* Add for multi controller case */ - spin_lock(&index_lock); - chip->index = chip_index++; - spin_unlock(&index_lock); - for (i = 0;i < slots;i++) { ret = sdhci_probe_slot(pdev, i); if (ret) { @@ -1654,8 +1688,6 @@ static int __init sdhci_drv_init(void) ": Secure Digital Host Controller Interface driver\n"); printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); - spin_lock_init(&index_lock); - return pci_register_driver(&sdhci_driver); } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index d5a38f1..7fb02e1 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -168,6 +168,10 @@ struct sdhci_host { struct sdhci_chip *chip; struct mmc_host *mmc; /* MMC structure */ +#ifdef CONFIG_LEDS_CLASS + struct led_classdev led; /* LED control */ +#endif + spinlock_t lock; /* Mutex */ int flags; /* Host attributes */ @@ -190,8 +194,6 @@ struct sdhci_host { int offset; /* Offset into current sg */ int remain; /* Bytes left in current */ - char slot_descr[20]; /* Name for reservations */ - int irq; /* Device IRQ */ int bar; /* PCI BAR index */ unsigned long addr; /* Bus address */ @@ -208,7 +210,6 @@ struct sdhci_chip { unsigned long quirks; - int index; /* Index for chip0, chip1 ...*/ int num_slots; /* Slots on controller */ struct sdhci_host *hosts[0]; /* Pointers to hosts */ };