summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-06 14:54:54 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-06 14:54:54 -0800
commit2442d3109943bafbdfc4f0495e3d10eeedc8390c (patch)
tree9700491eb6ca418ee226c5d8438464a1a2c87281 /drivers
parent02aedd69e2ef31b0fca1e8960cb1e7fd0c343110 (diff)
parentf9d429a2e579ed7c51c49a81265f7e7d2c59c197 (diff)
downloadlinux-2442d3109943bafbdfc4f0495e3d10eeedc8390c.tar.gz
linux-2442d3109943bafbdfc4f0495e3d10eeedc8390c.tar.bz2
linux-2442d3109943bafbdfc4f0495e3d10eeedc8390c.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (32 commits) mmc: tifm: replace kmap with page_address mmc: sdhci: fix voltage ocr mmc: sdhci: replace kmap with page_address mmc: wbsd: replace kmap with page_address mmc: handle pci_enable_device() return value in sdhci mmc: Proper unclaim in mmc_block mmc: change wbsd mailing list mmc: Graceful fallback for fancy features mmc: Handle wbsd's stupid command list mmc: Allow host drivers to specify max block count mmc: Allow host drivers to specify a max block size tifm_sd: add suspend and resume functionality tifm_core: add suspend/resume infrastructure for tifm devices tifm_7xx1: prettify tifm_7xx1: recognize device 0xac8f as supported tifm_7xx1: switch from workqueue to kthread tifm_7xx1: Merge media insert and media remove functions tifm_7xx1: simplify eject function Add dummy_signal_irq function to save check in ISR Remove unused return value from signal_irq callback ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/tifm_7xx1.c402
-rw-r--r--drivers/misc/tifm_core.c65
-rw-r--r--drivers/mmc/at91_mci.c3
-rw-r--r--drivers/mmc/au1xmmc.c13
-rw-r--r--drivers/mmc/imxmmc.c4
-rw-r--r--drivers/mmc/mmc.c182
-rw-r--r--drivers/mmc/mmc_block.c15
-rw-r--r--drivers/mmc/mmc_queue.c2
-rw-r--r--drivers/mmc/mmc_sysfs.c2
-rw-r--r--drivers/mmc/mmci.c15
-rw-r--r--drivers/mmc/omap.c6
-rw-r--r--drivers/mmc/pxamci.c10
-rw-r--r--drivers/mmc/sdhci.c91
-rw-r--r--drivers/mmc/sdhci.h2
-rw-r--r--drivers/mmc/tifm_sd.c487
-rw-r--r--drivers/mmc/wbsd.c102
-rw-r--r--drivers/mmc/wbsd.h1
17 files changed, 847 insertions, 555 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 2ab7add78f94..e21e490fedb0 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,66 +11,25 @@
#include <linux/tifm.h>
#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
#define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
{
- int cnt;
- unsigned long flags;
-
- spin_lock_irqsave(&fm->lock, flags);
- if (!fm->inhibit_new_cards) {
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (fm->sockets[cnt] == sock) {
- fm->remove_mask |= (1 << cnt);
- queue_work(fm->wq, &fm->media_remover);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&fm->lock, flags);
-}
-
-static void tifm_7xx1_remove_media(struct work_struct *work)
-{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_remover);
unsigned long flags;
- int cnt;
- struct tifm_dev *sock;
- if (!class_device_get(&fm->cdev))
- return;
spin_lock_irqsave(&fm->lock, flags);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
- printk(KERN_INFO DRIVER_NAME
- ": demand removing card from socket %d\n", cnt);
- sock = fm->sockets[cnt];
- fm->sockets[cnt] = NULL;
- fm->remove_mask &= ~(1 << cnt);
-
- writel(0x0e00, sock->addr + SOCK_CONTROL);
-
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
-
- spin_unlock_irqrestore(&fm->lock, flags);
- device_unregister(&sock->dev);
- spin_lock_irqsave(&fm->lock, flags);
- }
- }
+ fm->socket_change_set |= 1 << sock->socket_id;
+ wake_up_all(&fm->change_set_notify);
spin_unlock_irqrestore(&fm->lock, flags);
- class_device_put(&fm->cdev);
}
static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
{
struct tifm_adapter *fm = dev_id;
+ struct tifm_dev *sock;
unsigned int irq_status;
unsigned int sock_irq_status, cnt;
@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
if (irq_status & TIFM_IRQ_ENABLE) {
writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- sock_irq_status = (irq_status >> cnt) &
- (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
-
- if (fm->sockets[cnt]) {
- if (sock_irq_status &&
- fm->sockets[cnt]->signal_irq)
- sock_irq_status = fm->sockets[cnt]->
- signal_irq(fm->sockets[cnt],
- sock_irq_status);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ sock = fm->sockets[cnt];
+ sock_irq_status = (irq_status >> cnt)
+ & (TIFM_IRQ_FIFOMASK(1)
+ | TIFM_IRQ_CARDMASK(1));
- if (irq_status & (1 << cnt))
- fm->remove_mask |= 1 << cnt;
- } else {
- if (irq_status & (1 << cnt))
- fm->insert_mask |= 1 << cnt;
- }
+ if (sock && sock_irq_status)
+ sock->signal_irq(sock, sock_irq_status);
}
+
+ fm->socket_change_set |= irq_status
+ & ((1 << fm->num_sockets) - 1);
}
writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
- if (!fm->inhibit_new_cards) {
- if (!fm->remove_mask && !fm->insert_mask) {
- writel(TIFM_IRQ_ENABLE,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- } else {
- queue_work(fm->wq, &fm->media_remover);
- queue_work(fm->wq, &fm->media_inserter);
- }
- }
+ if (!fm->socket_change_set)
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+ else
+ wake_up_all(&fm->change_set_notify);
spin_unlock(&fm->lock);
return IRQ_HANDLED;
}
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
+static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
+ int is_x2)
{
unsigned int s_state;
int cnt;
@@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
writel(0x0e00, sock_addr + SOCK_CONTROL);
for (cnt = 0; cnt < 100; cnt++) {
- if (!(TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if (!(TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
}
for (cnt = 0; cnt < 100; cnt++) {
- if ((TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if ((TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
return base_addr + ((sock_num + 1) << 10);
}
-static void tifm_7xx1_insert_media(struct work_struct *work)
+static int tifm_7xx1_switch_media(void *data)
{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_inserter);
+ struct tifm_adapter *fm = data;
unsigned long flags;
tifm_media_id media_id;
char *card_name = "xx";
- int cnt, ok_to_register;
- unsigned int insert_mask;
- struct tifm_dev *new_sock = NULL;
+ int cnt, rc;
+ struct tifm_dev *sock;
+ unsigned int socket_change_set;
- if (!class_device_get(&fm->cdev))
- return;
- spin_lock_irqsave(&fm->lock, flags);
- insert_mask = fm->insert_mask;
- fm->insert_mask = 0;
- if (fm->inhibit_new_cards) {
+ while (1) {
+ rc = wait_event_interruptible(fm->change_set_notify,
+ fm->socket_change_set);
+ if (rc == -ERESTARTSYS)
+ try_to_freeze();
+
+ spin_lock_irqsave(&fm->lock, flags);
+ socket_change_set = fm->socket_change_set;
+ fm->socket_change_set = 0;
+
+ dev_dbg(fm->dev, "checking media set %x\n",
+ socket_change_set);
+
+ if (kthread_should_stop())
+ socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
- class_device_put(&fm->cdev);
- return;
- }
- spin_unlock_irqrestore(&fm->lock, flags);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (!(insert_mask & (1 << cnt)))
+ if (!socket_change_set)
continue;
- media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
- fm->max_sockets == 2);
- if (media_id) {
- ok_to_register = 0;
- new_sock = tifm_alloc_device(fm, cnt);
- if (new_sock) {
- new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
- cnt);
- new_sock->media_id = media_id;
- switch (media_id) {
- case 1:
- card_name = "xd";
- break;
- case 2:
- card_name = "ms";
- break;
- case 3:
- card_name = "sd";
- break;
- default:
- break;
- }
- snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
- "tifm_%s%u:%u", card_name, fm->id, cnt);
+ spin_lock_irqsave(&fm->lock, flags);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (!(socket_change_set & (1 << cnt)))
+ continue;
+ sock = fm->sockets[cnt];
+ if (sock) {
printk(KERN_INFO DRIVER_NAME
- ": %s card detected in socket %d\n",
- card_name, cnt);
+ ": demand removing card from socket %d\n",
+ cnt);
+ fm->sockets[cnt] = NULL;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ device_unregister(&sock->dev);
spin_lock_irqsave(&fm->lock, flags);
- if (!fm->sockets[cnt]) {
- fm->sockets[cnt] = new_sock;
- ok_to_register = 1;
+ writel(0x0e00,
+ tifm_7xx1_sock_addr(fm->addr, cnt)
+ + SOCK_CONTROL);
+ }
+ if (kthread_should_stop())
+ continue;
+
+ spin_unlock_irqrestore(&fm->lock, flags);
+ media_id = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
+ if (media_id) {
+ sock = tifm_alloc_device(fm);
+ if (sock) {
+ sock->addr = tifm_7xx1_sock_addr(fm->addr,
+ cnt);
+ sock->media_id = media_id;
+ sock->socket_id = cnt;
+ switch (media_id) {
+ case 1:
+ card_name = "xd";
+ break;
+ case 2:
+ card_name = "ms";
+ break;
+ case 3:
+ card_name = "sd";
+ break;
+ default:
+ tifm_free_device(&sock->dev);
+ spin_lock_irqsave(&fm->lock, flags);
+ continue;
+ }
+ snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+ "tifm_%s%u:%u", card_name,
+ fm->id, cnt);
+ printk(KERN_INFO DRIVER_NAME
+ ": %s card detected in socket %d\n",
+ card_name, cnt);
+ if (!device_register(&sock->dev)) {
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->sockets[cnt]) {
+ fm->sockets[cnt] = sock;
+ sock = NULL;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+ if (sock)
+ tifm_free_device(&sock->dev);
}
+ spin_lock_irqsave(&fm->lock, flags);
+ }
+ }
+
+ if (!kthread_should_stop()) {
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+ } else {
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt])
+ fm->socket_change_set |= 1 << cnt;
+ }
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
spin_unlock_irqrestore(&fm->lock, flags);
- if (!ok_to_register ||
- device_register(&new_sock->dev)) {
- spin_lock_irqsave(&fm->lock, flags);
- fm->sockets[cnt] = NULL;
- spin_unlock_irqrestore(&fm->lock,
- flags);
- tifm_free_device(&new_sock->dev);
- }
}
}
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
}
-
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
- class_device_put(&fm->cdev);
+ return 0;
}
+#ifdef CONFIG_PM
+
static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
{
- struct tifm_adapter *fm = pci_get_drvdata(dev);
- unsigned long flags;
+ dev_dbg(&dev->dev, "suspending host\n");
- spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 1;
- fm->remove_mask = 0xf;
- fm->insert_mask = 0;
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&fm->lock, flags);
- flush_workqueue(fm->wq);
-
- tifm_7xx1_remove_media(&fm->media_remover);
-
- pci_set_power_state(dev, PCI_D3hot);
- pci_disable_device(dev);
- pci_save_state(dev);
+ pci_save_state(dev);
+ pci_enable_wake(dev, pci_choose_state(dev, state), 0);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
static int tifm_7xx1_resume(struct pci_dev *dev)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
+ int cnt, rc;
unsigned long flags;
+ tifm_media_id new_ids[fm->num_sockets];
+ pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- pci_enable_device(dev);
- pci_set_power_state(dev, PCI_D0);
- pci_set_master(dev);
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+ pci_set_master(dev);
+ dev_dbg(&dev->dev, "resuming host\n");
+
+ for (cnt = 0; cnt < fm->num_sockets; cnt++)
+ new_ids[cnt] = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 0;
- writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- fm->insert_mask = 0xf;
+ fm->socket_change_set = 0;
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt]) {
+ if (fm->sockets[cnt]->media_id == new_ids[cnt])
+ fm->socket_change_set |= 1 << cnt;
+
+ fm->sockets[cnt]->media_id = new_ids[cnt];
+ }
+ }
+
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
+ fm->socket_change_set = 0;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+
+ wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+
+ spin_lock_irqsave(&fm->lock, flags);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ fm->socket_change_set = 0;
+
spin_unlock_irqrestore(&fm->lock, flags);
return 0;
}
+#else
+
+#define tifm_7xx1_suspend NULL
+#define tifm_7xx1_resume NULL
+
+#endif /* CONFIG_PM */
+
static int tifm_7xx1_probe(struct pci_dev *dev,
- const struct pci_device_id *dev_id)
+ const struct pci_device_id *dev_id)
{
struct tifm_adapter *fm;
int pci_dev_busy = 0;
@@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
}
fm->dev = &dev->dev;
- fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
- fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
- GFP_KERNEL);
+ fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
+ ? 4 : 2;
+ fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
+ GFP_KERNEL);
if (!fm->sockets)
goto err_out_free;
- INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media);
- INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
fm->eject = tifm_7xx1_eject;
pci_set_drvdata(dev, fm);
fm->addr = ioremap(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
+ pci_resource_len(dev, 0));
if (!fm->addr)
goto err_out_free;
@@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
if (rc)
goto err_out_unmap;
- rc = tifm_add_adapter(fm);
+ init_waitqueue_head(&fm->change_set_notify);
+ rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
if (rc)
goto err_out_irq;
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
-
- fm->insert_mask = 0xf;
-
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ wake_up_process(fm->media_switcher);
return 0;
err_out_irq:
@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
struct tifm_adapter *fm = pci_get_drvdata(dev);
unsigned long flags;
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ mmiowb();
+ free_irq(dev->irq, fm);
+
spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 1;
- fm->remove_mask = 0xf;
- fm->insert_mask = 0;
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ fm->socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
- flush_workqueue(fm->wq);
-
- tifm_7xx1_remove_media(&fm->media_remover);
-
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- free_irq(dev->irq, fm);
+ kthread_stop(fm->media_switcher);
tifm_remove_adapter(fm);
@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
}
static struct pci_device_id tifm_7xx1_pci_tbl [] = {
- { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- 0 }, /* xx21 - the one I have */
- { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- 0 }, /* xx12 - should be also supported */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
{ }
};
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d61df5c3ac36..6b10ebe9d936 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,7 +14,7 @@
#include <linux/idr.h>
#define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);
@@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp,
return 0;
}
+#ifdef CONFIG_PM
+
+static int tifm_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->suspend)
+ return drv->suspend(fm_dev, state);
+ return 0;
+}
+
+static int tifm_device_resume(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->resume)
+ return drv->resume(fm_dev);
+ return 0;
+}
+
+#else
+
+#define tifm_device_suspend NULL
+#define tifm_device_resume NULL
+
+#endif /* CONFIG_PM */
+
static struct bus_type tifm_bus_type = {
.name = "tifm",
.match = tifm_match,
.uevent = tifm_uevent,
+ .suspend = tifm_device_suspend,
+ .resume = tifm_device_resume
};
static void tifm_free(struct class_device *cdev)
@@ -71,8 +102,6 @@ static void tifm_free(struct class_device *cdev)
struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
kfree(fm->sockets);
- if (fm->wq)
- destroy_workqueue(fm->wq);
kfree(fm);
}
@@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
}
EXPORT_SYMBOL(tifm_free_adapter);
-int tifm_add_adapter(struct tifm_adapter *fm)
+int tifm_add_adapter(struct tifm_adapter *fm,
+ int (*mediathreadfn)(void *data))
{
int rc;
@@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
spin_unlock(&tifm_adapter_lock);
if (!rc) {
snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
- strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+ fm->media_switcher = kthread_create(mediathreadfn,
+ fm, "tifm/%u", fm->id);
- fm->wq = create_singlethread_workqueue(fm->wq_name);
- if (fm->wq)
+ if (!IS_ERR(fm->media_switcher))
return class_device_add(&fm->cdev);
spin_lock(&tifm_adapter_lock);
@@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter);
void tifm_free_device(struct device *dev)
{
struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- if (fm_dev->wq)
- destroy_workqueue(fm_dev->wq);
kfree(fm_dev);
}
EXPORT_SYMBOL(tifm_free_device);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+static void tifm_dummy_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
+{
+ return;
+}
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
{
struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
if (dev) {
spin_lock_init(&dev->lock);
- snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
- dev->wq = create_singlethread_workqueue(dev->wq_name);
- if (!dev->wq) {
- kfree(dev);
- return NULL;
- }
+
dev->dev.parent = fm->dev;
dev->dev.bus = &tifm_bus_type;
dev->dev.release = tifm_free_device;
+ dev->signal_irq = tifm_dummy_signal_irq;
}
return dev;
}
@@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev)
struct tifm_driver *drv = fm_dev->drv;
if (drv) {
+ fm_dev->signal_irq = tifm_dummy_signal_irq;
if (drv->remove)
drv->remove(fm_dev);
fm_dev->drv = NULL;
@@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv)
drv->driver.bus = &tifm_bus_type;
drv->driver.probe = tifm_device_probe;
drv->driver.remove = tifm_device_remove;
+ drv->driver.suspend = tifm_device_suspend;
+ drv->driver.resume = tifm_device_resume;
return driver_register(&drv->driver);
}
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index aa152f31851e..2ce50f38e3c7 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -823,6 +823,9 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_BYTEBLOCK;
+ mmc->max_blk_size = 4095;
+ mmc->max_blk_count = mmc->max_req_size;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->buffer = NULL;
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 800527cf40d5..b834be261ab7 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
? 1 : 0;
}
-static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
{
+ struct au1xmmc_host *host = mmc_priv(mmc);
return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
? 1 : 0;
}
@@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ break;
case MMC_RSP_R1:
mmccmd |= SD_CMD_RT_1;
break;
@@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
case MMC_RSP_R3:
mmccmd |= SD_CMD_RT_3;
break;
+ default:
+ printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+ mmc_resp_type(cmd));
+ return MMC_ERR_INVALID;
}
switch(cmd->opcode) {
@@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request,
.set_ios = au1xmmc_set_ios,
+ .get_ro = au1xmmc_card_readonly,
};
static int __devinit au1xmmc_probe(struct platform_device *pdev)
@@ -914,6 +922,9 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 512;
+
mmc->ocr_avail = AU1XMMC_OCR;
host = mmc_priv(mmc);
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index bfb9ff693208..b060d4bfba29 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev)
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
- mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */
mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 65535;
host = mmc_priv(mmc);
host->mmc = mmc;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6f2a282e2b97..5046a1661342 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
- WARN_ON(host->card_busy == NULL);
+ WARN_ON(!host->claimed);
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
+ BUG_ON(mrq->data->blksz > host->max_blk_size);
+ BUG_ON(mrq->data->blocks > host->max_blk_count);
+ BUG_ON(mrq->data->blocks * mrq->data->blksz >
+ host->max_req_size);
+
mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
@@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
int i, err;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
BUG_ON(retries < 0);
err = MMC_ERR_INVALID;
@@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
else
limit_us = 100000;
- if (timeout_us > limit_us) {
+ /*
+ * SDHC cards always use these fixed values.
+ */
+ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0;
}
@@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (host->card_busy == NULL)
+ if (!host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
- host->card_busy = card;
+ host->claimed = 1;
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
@@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
- host->card_busy = NULL;
+ host->claimed = 0;
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
@@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width);
-
+
host->ops->set_ios(host, ios);
}
@@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int err;
struct mmc_command cmd;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
if (host->card_selected == card)
return MMC_ERR_NONE;
@@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card)
if (mmc_card_sd(card)) {
csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 0) {
+
+ switch (csd_struct) {
+ case 0:
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ break;
+ case 1:
+ /*
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values