diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 100 |
1 files changed, 70 insertions, 30 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4b673aa2dc3c..07c2048b230b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver | 2 | * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver |
3 | * | 3 | * |
4 | * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. | 4 | * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
20 | #include <linux/scatterlist.h> | 20 | #include <linux/scatterlist.h> |
21 | 21 | ||
22 | #include <linux/leds.h> | ||
23 | |||
22 | #include <linux/mmc/host.h> | 24 | #include <linux/mmc/host.h> |
23 | 25 | ||
24 | #include "sdhci.h" | 26 | #include "sdhci.h" |
@@ -30,10 +32,6 @@ | |||
30 | 32 | ||
31 | static unsigned int debug_quirks = 0; | 33 | static unsigned int debug_quirks = 0; |
32 | 34 | ||
33 | /* For multi controllers in one platform case */ | ||
34 | static u16 chip_index = 0; | ||
35 | static spinlock_t index_lock; | ||
36 | |||
37 | /* | 35 | /* |
38 | * Different quirks to handle when the hardware deviates from a strict | 36 | * Different quirks to handle when the hardware deviates from a strict |
39 | * interpretation of the SDHCI specification. | 37 | * interpretation of the SDHCI specification. |
@@ -43,7 +41,7 @@ static spinlock_t index_lock; | |||
43 | #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) | 41 | #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) |
44 | /* Controller has bad caps bits, but really supports DMA */ | 42 | /* Controller has bad caps bits, but really supports DMA */ |
45 | #define SDHCI_QUIRK_FORCE_DMA (1<<1) | 43 | #define SDHCI_QUIRK_FORCE_DMA (1<<1) |
46 | /* Controller doesn't like some resets when there is no card inserted. */ | 44 | /* Controller doesn't like to be reset when there is no card inserted. */ |
47 | #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) | 45 | #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) |
48 | /* Controller doesn't like clearing the power reg before a change */ | 46 | /* Controller doesn't like clearing the power reg before a change */ |
49 | #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) | 47 | #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) |
@@ -71,13 +69,21 @@ static const struct pci_device_id pci_ids[] __devinitdata = { | |||
71 | { | 69 | { |
72 | .vendor = PCI_VENDOR_ID_RICOH, | 70 | .vendor = PCI_VENDOR_ID_RICOH, |
73 | .device = PCI_DEVICE_ID_RICOH_R5C822, | 71 | .device = PCI_DEVICE_ID_RICOH_R5C822, |
74 | .subvendor = PCI_ANY_ID, | 72 | .subvendor = PCI_VENDOR_ID_SAMSUNG, |
75 | .subdevice = PCI_ANY_ID, | 73 | .subdevice = PCI_ANY_ID, |
76 | .driver_data = SDHCI_QUIRK_FORCE_DMA | | 74 | .driver_data = SDHCI_QUIRK_FORCE_DMA | |
77 | SDHCI_QUIRK_NO_CARD_NO_RESET, | 75 | SDHCI_QUIRK_NO_CARD_NO_RESET, |
78 | }, | 76 | }, |
79 | 77 | ||
80 | { | 78 | { |
79 | .vendor = PCI_VENDOR_ID_RICOH, | ||
80 | .device = PCI_DEVICE_ID_RICOH_R5C822, | ||
81 | .subvendor = PCI_ANY_ID, | ||
82 | .subdevice = PCI_ANY_ID, | ||
83 | .driver_data = SDHCI_QUIRK_FORCE_DMA, | ||
84 | }, | ||
85 | |||
86 | { | ||
81 | .vendor = PCI_VENDOR_ID_TI, | 87 | .vendor = PCI_VENDOR_ID_TI, |
82 | .device = PCI_DEVICE_ID_TI_XX21_XX11_SD, | 88 | .device = PCI_DEVICE_ID_TI_XX21_XX11_SD, |
83 | .subvendor = PCI_ANY_ID, | 89 | .subvendor = PCI_ANY_ID, |
@@ -256,6 +262,24 @@ static void sdhci_deactivate_led(struct sdhci_host *host) | |||
256 | writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); | 262 | writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); |
257 | } | 263 | } |
258 | 264 | ||
265 | #ifdef CONFIG_LEDS_CLASS | ||
266 | static void sdhci_led_control(struct led_classdev *led, | ||
267 | enum led_brightness brightness) | ||
268 | { | ||
269 | struct sdhci_host *host = container_of(led, struct sdhci_host, led); | ||
270 | unsigned long flags; | ||
271 | |||
272 | spin_lock_irqsave(&host->lock, flags); | ||
273 | |||
274 | if (brightness == LED_OFF) | ||
275 | sdhci_deactivate_led(host); | ||
276 | else | ||
277 | sdhci_activate_led(host); | ||
278 | |||
279 | spin_unlock_irqrestore(&host->lock, flags); | ||
280 | } | ||
281 | #endif | ||
282 | |||
259 | /*****************************************************************************\ | 283 | /*****************************************************************************\ |
260 | * * | 284 | * * |
261 | * Core functions * | 285 | * Core functions * |
@@ -773,7 +797,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
773 | 797 | ||
774 | WARN_ON(host->mrq != NULL); | 798 | WARN_ON(host->mrq != NULL); |
775 | 799 | ||
800 | #ifndef CONFIG_LEDS_CLASS | ||
776 | sdhci_activate_led(host); | 801 | sdhci_activate_led(host); |
802 | #endif | ||
777 | 803 | ||
778 | host->mrq = mrq; | 804 | host->mrq = mrq; |
779 | 805 | ||
@@ -965,7 +991,9 @@ static void sdhci_tasklet_finish(unsigned long param) | |||
965 | host->cmd = NULL; | 991 | host->cmd = NULL; |
966 | host->data = NULL; | 992 | host->data = NULL; |
967 | 993 | ||
994 | #ifndef CONFIG_LEDS_CLASS | ||
968 | sdhci_deactivate_led(host); | 995 | sdhci_deactivate_led(host); |
996 | #endif | ||
969 | 997 | ||
970 | mmiowb(); | 998 | mmiowb(); |
971 | spin_unlock_irqrestore(&host->lock, flags); | 999 | spin_unlock_irqrestore(&host->lock, flags); |
@@ -1105,7 +1133,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
1105 | goto out; | 1133 | goto out; |
1106 | } | 1134 | } |
1107 | 1135 | ||
1108 | DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask); | 1136 | DBG("*** %s got interrupt: 0x%08x\n", |
1137 | mmc_hostname(host->mmc), intmask); | ||
1109 | 1138 | ||
1110 | if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { | 1139 | if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { |
1111 | writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), | 1140 | writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), |
@@ -1235,7 +1264,7 @@ static int sdhci_resume (struct pci_dev *pdev) | |||
1235 | if (chip->hosts[i]->flags & SDHCI_USE_DMA) | 1264 | if (chip->hosts[i]->flags & SDHCI_USE_DMA) |
1236 | pci_set_master(pdev); | 1265 | pci_set_master(pdev); |
1237 | ret = request_irq(chip->hosts[i]->irq, sdhci_irq, | 1266 | ret = request_irq(chip->hosts[i]->irq, sdhci_irq, |
1238 | IRQF_SHARED, chip->hosts[i]->slot_descr, | 1267 | IRQF_SHARED, mmc_hostname(chip->hosts[i]->mmc), |
1239 | chip->hosts[i]); | 1268 | chip->hosts[i]); |
1240 | if (ret) | 1269 | if (ret) |
1241 | return ret; | 1270 | return ret; |
@@ -1324,9 +1353,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1324 | 1353 | ||
1325 | DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq); | 1354 | DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq); |
1326 | 1355 | ||
1327 | snprintf(host->slot_descr, 20, "sdhc%d:slot%d", chip->index, slot); | 1356 | ret = pci_request_region(pdev, host->bar, mmc_hostname(mmc)); |
1328 | |||
1329 | ret = pci_request_region(pdev, host->bar, host->slot_descr); | ||
1330 | if (ret) | 1357 | if (ret) |
1331 | goto free; | 1358 | goto free; |
1332 | 1359 | ||
@@ -1343,7 +1370,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1343 | version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; | 1370 | version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; |
1344 | if (version > 1) { | 1371 | if (version > 1) { |
1345 | printk(KERN_ERR "%s: Unknown controller version (%d). " | 1372 | printk(KERN_ERR "%s: Unknown controller version (%d). " |
1346 | "You may experience problems.\n", host->slot_descr, | 1373 | "You may experience problems.\n", mmc_hostname(mmc), |
1347 | version); | 1374 | version); |
1348 | } | 1375 | } |
1349 | 1376 | ||
@@ -1366,13 +1393,13 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1366 | (host->flags & SDHCI_USE_DMA)) { | 1393 | (host->flags & SDHCI_USE_DMA)) { |
1367 | printk(KERN_WARNING "%s: Will use DMA " | 1394 | printk(KERN_WARNING "%s: Will use DMA " |
1368 | "mode even though HW doesn't fully " | 1395 | "mode even though HW doesn't fully " |
1369 | "claim to support it.\n", host->slot_descr); | 1396 | "claim to support it.\n", mmc_hostname(mmc)); |
1370 | } | 1397 | } |
1371 | 1398 | ||
1372 | if (host->flags & SDHCI_USE_DMA) { | 1399 | if (host->flags & SDHCI_USE_DMA) { |
1373 | if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { | 1400 | if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { |
1374 | printk(KERN_WARNING "%s: No suitable DMA available. " | 1401 | printk(KERN_WARNING "%s: No suitable DMA available. " |
1375 | "Falling back to PIO.\n", host->slot_descr); | 1402 | "Falling back to PIO.\n", mmc_hostname(mmc)); |
1376 | host->flags &= ~SDHCI_USE_DMA; | 1403 | host->flags &= ~SDHCI_USE_DMA; |
1377 | } | 1404 | } |
1378 | } | 1405 | } |
@@ -1386,7 +1413,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1386 | (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; | 1413 | (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; |
1387 | if (host->max_clk == 0) { | 1414 | if (host->max_clk == 0) { |
1388 | printk(KERN_ERR "%s: Hardware doesn't specify base clock " | 1415 | printk(KERN_ERR "%s: Hardware doesn't specify base clock " |
1389 | "frequency.\n", host->slot_descr); | 1416 | "frequency.\n", mmc_hostname(mmc)); |
1390 | ret = -ENODEV; | 1417 | ret = -ENODEV; |
1391 | goto unmap; | 1418 | goto unmap; |
1392 | } | 1419 | } |
@@ -1396,7 +1423,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1396 | (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; | 1423 | (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; |
1397 | if (host->timeout_clk == 0) { | 1424 | if (host->timeout_clk == 0) { |
1398 | printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " | 1425 | printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " |
1399 | "frequency.\n", host->slot_descr); | 1426 | "frequency.\n", mmc_hostname(mmc)); |
1400 | ret = -ENODEV; | 1427 | ret = -ENODEV; |
1401 | goto unmap; | 1428 | goto unmap; |
1402 | } | 1429 | } |
@@ -1424,7 +1451,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1424 | 1451 | ||
1425 | if (mmc->ocr_avail == 0) { | 1452 | if (mmc->ocr_avail == 0) { |
1426 | printk(KERN_ERR "%s: Hardware doesn't report any " | 1453 | printk(KERN_ERR "%s: Hardware doesn't report any " |
1427 | "support voltages.\n", host->slot_descr); | 1454 | "support voltages.\n", mmc_hostname(mmc)); |
1428 | ret = -ENODEV; | 1455 | ret = -ENODEV; |
1429 | goto unmap; | 1456 | goto unmap; |
1430 | } | 1457 | } |
@@ -1458,8 +1485,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1458 | */ | 1485 | */ |
1459 | mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; | 1486 | mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; |
1460 | if (mmc->max_blk_size >= 3) { | 1487 | if (mmc->max_blk_size >= 3) { |
1461 | printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n", | 1488 | printk(KERN_WARNING "%s: Invalid maximum block size, " |
1462 | host->slot_descr); | 1489 | "assuming 512 bytes\n", mmc_hostname(mmc)); |
1463 | mmc->max_blk_size = 512; | 1490 | mmc->max_blk_size = 512; |
1464 | } else | 1491 | } else |
1465 | mmc->max_blk_size = 512 << mmc->max_blk_size; | 1492 | mmc->max_blk_size = 512 << mmc->max_blk_size; |
@@ -1480,7 +1507,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1480 | setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); | 1507 | setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); |
1481 | 1508 | ||
1482 | ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, | 1509 | ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, |
1483 | host->slot_descr, host); | 1510 | mmc_hostname(mmc), host); |
1484 | if (ret) | 1511 | if (ret) |
1485 | goto untasklet; | 1512 | goto untasklet; |
1486 | 1513 | ||
@@ -1490,16 +1517,32 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1490 | sdhci_dumpregs(host); | 1517 | sdhci_dumpregs(host); |
1491 | #endif | 1518 | #endif |
1492 | 1519 | ||
1520 | #ifdef CONFIG_LEDS_CLASS | ||
1521 | host->led.name = mmc_hostname(mmc); | ||
1522 | host->led.brightness = LED_OFF; | ||
1523 | host->led.default_trigger = mmc_hostname(mmc); | ||
1524 | host->led.brightness_set = sdhci_led_control; | ||
1525 | |||
1526 | ret = led_classdev_register(&pdev->dev, &host->led); | ||
1527 | if (ret) | ||
1528 | goto reset; | ||
1529 | #endif | ||
1530 | |||
1493 | mmiowb(); | 1531 | mmiowb(); |
1494 | 1532 | ||
1495 | mmc_add_host(mmc); | 1533 | mmc_add_host(mmc); |
1496 | 1534 | ||
1497 | printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc), | 1535 | printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", |
1498 | host->addr, host->irq, | 1536 | mmc_hostname(mmc), host->addr, host->irq, |
1499 | (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); | 1537 | (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); |
1500 | 1538 | ||
1501 | return 0; | 1539 | return 0; |
1502 | 1540 | ||
1541 | #ifdef CONFIG_LEDS_CLASS | ||
1542 | reset: | ||
1543 | sdhci_reset(host, SDHCI_RESET_ALL); | ||
1544 | free_irq(host->irq, host); | ||
1545 | #endif | ||
1503 | untasklet: | 1546 | untasklet: |
1504 | tasklet_kill(&host->card_tasklet); | 1547 | tasklet_kill(&host->card_tasklet); |
1505 | tasklet_kill(&host->finish_tasklet); | 1548 | tasklet_kill(&host->finish_tasklet); |
@@ -1527,6 +1570,10 @@ static void sdhci_remove_slot(struct pci_dev *pdev, int slot) | |||
1527 | 1570 | ||
1528 | mmc_remove_host(mmc); | 1571 | mmc_remove_host(mmc); |
1529 | 1572 | ||
1573 | #ifdef CONFIG_LEDS_CLASS | ||
1574 | led_classdev_unregister(&host->led); | ||
1575 | #endif | ||
1576 | |||
1530 | sdhci_reset(host, SDHCI_RESET_ALL); | 1577 | sdhci_reset(host, SDHCI_RESET_ALL); |
1531 | 1578 | ||
1532 | free_irq(host->irq, host); | 1579 | free_irq(host->irq, host); |
@@ -1589,11 +1636,6 @@ static int __devinit sdhci_probe(struct pci_dev *pdev, | |||
1589 | chip->num_slots = slots; | 1636 | chip->num_slots = slots; |
1590 | pci_set_drvdata(pdev, chip); | 1637 | pci_set_drvdata(pdev, chip); |
1591 | 1638 | ||
1592 | /* Add for multi controller case */ | ||
1593 | spin_lock(&index_lock); | ||
1594 | chip->index = chip_index++; | ||
1595 | spin_unlock(&index_lock); | ||
1596 | |||
1597 | for (i = 0;i < slots;i++) { | 1639 | for (i = 0;i < slots;i++) { |
1598 | ret = sdhci_probe_slot(pdev, i); | 1640 | ret = sdhci_probe_slot(pdev, i); |
1599 | if (ret) { | 1641 | if (ret) { |
@@ -1654,8 +1696,6 @@ static int __init sdhci_drv_init(void) | |||
1654 | ": Secure Digital Host Controller Interface driver\n"); | 1696 | ": Secure Digital Host Controller Interface driver\n"); |
1655 | printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); | 1697 | printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); |
1656 | 1698 | ||
1657 | spin_lock_init(&index_lock); | ||
1658 | |||
1659 | return pci_register_driver(&sdhci_driver); | 1699 | return pci_register_driver(&sdhci_driver); |
1660 | } | 1700 | } |
1661 | 1701 | ||