Commit 2442d310 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 02aedd69 f9d429a2
...@@ -3647,7 +3647,7 @@ S: Maintained ...@@ -3647,7 +3647,7 @@ S: Maintained
W83L51xD SD/MMC CARD INTERFACE DRIVER W83L51xD SD/MMC CARD INTERFACE DRIVER
P: Pierre Ossman P: Pierre Ossman
M: drzeus-wbsd@drzeus.cx M: drzeus-wbsd@drzeus.cx
L: wbsd-devel@list.drzeus.cx L: linux-kernel@vger.kernel.org
W: http://projects.drzeus.cx/wbsd W: http://projects.drzeus.cx/wbsd
S: Maintained S: Maintained
......
...@@ -11,66 +11,25 @@ ...@@ -11,66 +11,25 @@
#include <linux/tifm.h> #include <linux/tifm.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/freezer.h>
#define DRIVER_NAME "tifm_7xx1" #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) 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; unsigned long flags;
int cnt;
struct tifm_dev *sock;
if (!class_device_get(&fm->cdev))
return;
spin_lock_irqsave(&fm->lock, flags); spin_lock_irqsave(&fm->lock, flags);
for (cnt = 0; cnt < fm->max_sockets; cnt++) { fm->socket_change_set |= 1 << sock->socket_id;
if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) { wake_up_all(&fm->change_set_notify);
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);
}
}
spin_unlock_irqrestore(&fm->lock, flags); spin_unlock_irqrestore(&fm->lock, flags);
class_device_put(&fm->cdev);
} }
static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
{ {
struct tifm_adapter *fm = dev_id; struct tifm_adapter *fm = dev_id;
struct tifm_dev *sock;
unsigned int irq_status; unsigned int irq_status;
unsigned int sock_irq_status, cnt; unsigned int sock_irq_status, cnt;
...@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) ...@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
if (irq_status & TIFM_IRQ_ENABLE) { if (irq_status & TIFM_IRQ_ENABLE) {
writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
for (cnt = 0; cnt < fm->max_sockets; cnt++) { for (cnt = 0; cnt < fm->num_sockets; cnt++) {
sock_irq_status = (irq_status >> cnt) & sock = fm->sockets[cnt];
(TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); sock_irq_status = (irq_status >> cnt)
& (TIFM_IRQ_FIFOMASK(1)
if (fm->sockets[cnt]) { | TIFM_IRQ_CARDMASK(1));
if (sock_irq_status &&
fm->sockets[cnt]->signal_irq)
sock_irq_status = fm->sockets[cnt]->
signal_irq(fm->sockets[cnt],
sock_irq_status);
if (irq_status & (1 << cnt)) if (sock && sock_irq_status)
fm->remove_mask |= 1 << cnt; sock->signal_irq(sock, sock_irq_status);
} else {
if (irq_status & (1 << cnt))
fm->insert_mask |= 1 << cnt;
}
} }
fm->socket_change_set |= irq_status
& ((1 << fm->num_sockets) - 1);
} }
writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
if (!fm->inhibit_new_cards) { if (!fm->socket_change_set)
if (!fm->remove_mask && !fm->insert_mask) { writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
writel(TIFM_IRQ_ENABLE, else
fm->addr + FM_SET_INTERRUPT_ENABLE); wake_up_all(&fm->change_set_notify);
} else {
queue_work(fm->wq, &fm->media_remover);
queue_work(fm->wq, &fm->media_inserter);
}
}
spin_unlock(&fm->lock); spin_unlock(&fm->lock);
return IRQ_HANDLED; 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; unsigned int s_state;
int cnt; int cnt;
...@@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is ...@@ -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); writel(0x0e00, sock_addr + SOCK_CONTROL);
for (cnt = 0; cnt < 100; cnt++) { for (cnt = 0; cnt < 100; cnt++) {
if (!(TIFM_SOCK_STATE_POWERED & if (!(TIFM_SOCK_STATE_POWERED
readl(sock_addr + SOCK_PRESENT_STATE))) & readl(sock_addr + SOCK_PRESENT_STATE)))
break; break;
msleep(10); msleep(10);
} }
...@@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is ...@@ -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++) { for (cnt = 0; cnt < 100; cnt++) {
if ((TIFM_SOCK_STATE_POWERED & if ((TIFM_SOCK_STATE_POWERED
readl(sock_addr + SOCK_PRESENT_STATE))) & readl(sock_addr + SOCK_PRESENT_STATE)))
break; break;
msleep(10); msleep(10);
} }
...@@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) ...@@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
return base_addr + ((sock_num + 1) << 10); 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 = struct tifm_adapter *fm = data;
container_of(work, struct tifm_adapter, media_inserter);
unsigned long flags; unsigned long flags;
tifm_media_id media_id; tifm_media_id media_id;
char *card_name = "xx"; char *card_name = "xx";
int cnt, ok_to_register; int cnt, rc;
unsigned int insert_mask; struct tifm_dev *sock;
struct tifm_dev *new_sock = NULL; unsigned int socket_change_set;
if (!class_device_get(&fm->cdev)) while (1) {
return; rc = wait_event_interruptible(fm->change_set_notify,
spin_lock_irqsave(&fm->lock, flags); fm->socket_change_set);
insert_mask = fm->insert_mask; if (rc == -ERESTARTSYS)
fm->insert_mask = 0; try_to_freeze();
if (fm->inhibit_new_cards) {
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); 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 (!socket_change_set)
if (!(insert_mask & (1 << cnt)))
continue; continue;
media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt), spin_lock_irqsave(&fm->lock, flags);
fm->max_sockets == 2); for (cnt = 0; cnt < fm->num_sockets; cnt++) {
if (media_id) { if (!(socket_change_set & (1 << cnt)))
ok_to_register = 0; continue;
new_sock = tifm_alloc_device(fm, cnt); sock = fm->sockets[cnt];
if (new_sock) { if (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);
printk(KERN_INFO DRIVER_NAME printk(KERN_INFO DRIVER_NAME
": %s card detected in socket %d\n", ": demand removing card from socket %d\n",
card_name, cnt); cnt);
fm->sockets[cnt] = NULL;
spin_unlock_irqrestore(&fm->lock, flags);
device_unregister(&sock->dev);
spin_lock_irqsave(&fm->lock, flags); spin_lock_irqsave(&fm->lock, flags);
if (!fm->sockets[cnt]) { writel(0x0e00,
fm->sockets[cnt] = new_sock; tifm_7xx1_sock_addr(fm->addr, cnt)
ok_to_register = 1; + 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); 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);
} }
return 0;
writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
class_device_put(&fm->cdev);
} }
#ifdef CONFIG_PM
static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
{ {
struct tifm_adapter *fm = pci_get_drvdata(dev); dev_dbg(&dev->dev, "suspending host\n");
unsigned long flags;
spin_lock_irqsave(&fm->lock, flags); pci_save_state(dev);
fm->inhibit_new_cards = 1; pci_enable_wake(dev, pci_choose_state(dev, state), 0);
fm->remove_mask = 0xf; pci_disable_device(dev);
fm->insert_mask = 0; pci_set_power_state(dev, pci_choose_state(dev, state));
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);
return 0; return 0;
} }
static int tifm_7xx1_resume(struct pci_dev *dev) static int tifm_7xx1_resume(struct pci_dev *dev)
{ {
struct tifm_adapter *fm = pci_get_drvdata(dev); struct tifm_adapter *fm = pci_get_drvdata(dev);
int cnt, rc;
unsigned long flags; unsigned long flags;
tifm_media_id new_ids[fm->num_sockets];
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev); pci_restore_state(dev);
pci_enable_device(dev); rc = pci_enable_device(dev);
pci_set_power_state(dev, PCI_D0); if (rc)
pci_set_master(dev); 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); spin_lock_irqsave(&fm->lock, flags);
fm->inhibit_new_cards = 0; fm->socket_change_set = 0;
writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); for (cnt = 0; cnt < fm->num_sockets; cnt++) {
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); if (fm->sockets[cnt]) {
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, if (fm->sockets[cnt]->media_id == new_ids[cnt])
fm->addr + FM_SET_INTERRUPT_ENABLE); fm->socket_change_set |= 1 << cnt;
fm->insert_mask = 0xf;
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); spin_unlock_irqrestore(&fm->lock, flags);
return 0; 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, 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; struct tifm_adapter *fm;
int pci_dev_busy = 0; int pci_dev_busy = 0;
...@@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev, ...@@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
} }
fm->dev = &dev->dev; fm->dev = &dev->dev;
fm->max_sockets = (dev->device == 0x803B) ? 2 : 4; fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets, ? 4 : 2;
GFP_KERNEL); fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
GFP_KERNEL);
if (!fm->sockets) if (!fm->sockets)
goto err_out_free; 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; fm->eject = tifm_7xx1_eject;
pci_set_drvdata(dev, fm); pci_set_drvdata(dev, fm);
fm->addr = ioremap(pci_resource_start(dev, 0), fm->addr = ioremap(pci_resource_start(dev, 0),
pci_resource_len(dev, 0)); pci_resource_len(dev, 0));
if (!fm->addr) if (!fm->addr)
goto err_out_free; goto err_out_free;
...@@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev, ...@@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
if (rc) if (rc)
goto err_out_unmap; 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) if (rc)
goto err_out_irq; goto err_out_irq;
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
fm->addr + FM_SET_INTERRUPT_ENABLE); fm->addr + FM_SET_INTERRUPT_ENABLE);
wake_up_process(fm->media_switcher);
fm->insert_mask = 0xf;
return 0; return 0;
err_out_irq: err_out_irq:
...@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev) ...@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
struct tifm_adapter *fm = pci_get_drvdata(dev); struct tifm_adapter *fm = pci_get_drvdata(dev);
unsigned long flags; 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); spin_lock_irqsave(&fm->lock, flags);
fm->inhibit_new_cards = 1; fm->socket_change_set = (1 << fm->num_sockets) - 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); spin_unlock_irqrestore(&fm->lock, flags);
flush_workqueue(fm->wq); kthread_stop(fm->media_switcher);
tifm_7xx1_remove_media(&fm->media_remover);
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
free_irq(dev->irq, fm);
tifm_remove_adapter(fm); tifm_remove_adapter(fm);
...@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev) ...@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
} }
static struct pci_device_id tifm_7xx1_pci_tbl [] = { static struct pci_device_id tifm_7xx1_pci_tbl [] = {
{ PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
0 }, /* xx21 - the one I have */ PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
{ PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
0 }, /* xx12 - should be also supported */ 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 },
{ } { }
}; };
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include <linux/idr.h> #include <linux/idr.h>
#define DRIVER_NAME "tifm_core" #define DRIVER_NAME "tifm_core"
#define DRIVER_VERSION "0.6" #define DRIVER_VERSION "0.7"
static DEFINE_IDR(tifm_adapter_idr); static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock); static DEFINE_SPINLOCK(tifm_adapter_lock);
...@@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp, ...@@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp,
return 0; 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 = { static struct bus_type tifm_bus_type = {
.name = "tifm", .name = "tifm",
.match = tifm_match, .match = tifm_match,
.uevent = tifm_uevent, .uevent = tifm_uevent,
.suspend = tifm_device_suspend,
.resume = tifm_device_resume
}; };
static void tifm_free(struct class_device *cdev) static void tifm_free(struct class_device *cdev)
...@@ -71,8 +102,6 @@ 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); struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
kfree(fm->sockets); kfree(fm->sockets);
if (fm->wq)
destroy_workqueue(fm->wq);
kfree(fm); kfree(fm);
} }
...@@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm) ...@@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
} }
EXPORT_SYMBOL(tifm_free_adapter); 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; int rc;
...@@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm) ...@@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
spin_unlock(&tifm_adapter_lock); spin_unlock(&tifm_adapter_lock);
if (!rc) { if (!rc) {
snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); 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 (!IS_ERR(fm->media_switcher))
if (fm->wq)
return class_device_add(&fm->cdev); return class_device_add(&fm->cdev);
spin_lock(&tifm_adapter_lock); spin_lock(&tifm_adapter_lock);
...@@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter); ...@@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter);
void tifm_free_device(struct device *dev) void tifm_free_device(struct device *dev)
{ {
struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, 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); kfree(fm_dev);
} }
EXPORT_SYMBOL(tifm_free_device); 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); struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
if (dev) { if (dev) {
spin_lock_init(&dev->lock); 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.parent = fm->dev;
dev->dev.bus = &tifm_bus_type; dev->dev.bus = &tifm_bus_type;
dev->dev.release = tifm_free_device; dev->dev.release = tifm_free_device;
dev->signal_irq = tifm_dummy_signal_irq;
} }
return dev; return dev;
} }
...@@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev) ...@@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev)
struct tifm_driver *drv = fm_dev->drv; struct tifm_driver *drv = fm_dev->drv;
if (drv) { if (drv) {
fm_dev->signal_irq = tifm_dummy_signal_irq;
if (drv->remove) if (drv->remove)
drv->remove(fm_dev); drv->remove(fm_dev);
fm_dev->drv = NULL; fm_dev->drv = NULL;
...@@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv) ...@@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv)
drv->driver.bus = &tifm_bus_type; drv->driver.bus = &tifm_bus_type;
drv->driver.probe = tifm_device_probe; drv->driver.probe = tifm_device_probe;
drv->driver.remove = tifm_device_remove; drv->driver.remove = tifm_device_remove;
drv->driver.suspend = tifm_device_suspend;
drv->driver.resume = tifm_device_resume;
return driver_register(&drv->driver); return driver_register(&drv->driver);
} }
......
...@@ -823,6 +823,9 @@ static int __init at91_mci_probe(struct platform_device *pdev) ...@@ -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->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_BYTEBLOCK; mmc->caps = MMC_CAP_BYTEBLOCK;
mmc->max_blk_size = 4095;
mmc->max_blk_count = mmc->max_req_size;
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
host->buffer = NULL; host->buffer = NULL;
......
...@@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host) ...@@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
? 1 : 0; ? 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) return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
? 1 : 0; ? 1 : 0;
} }
...@@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, ...@@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
switch (mmc_resp_type(cmd)) { switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE:
break;
case MMC_RSP_R1: case MMC_RSP_R1:
mmccmd |= SD_CMD_RT_1; mmccmd |= SD_CMD_RT_1;
break; break;
...@@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, ...@@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
case MMC_RSP_R3: case MMC_RSP_R3:
mmccmd |= SD_CMD_RT_3; mmccmd |= SD_CMD_RT_3;
break; break;
default:
printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
mmc_resp_type(cmd));
return MMC_ERR_INVALID;
} }
switch(cmd->opcode) { switch(cmd->opcode) {
...@@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host) ...@@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
static const struct mmc_host_ops au1xmmc_ops = { static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request, .request = au1xmmc_request,
.set_ios = au1xmmc_set_ios, .set_ios = au1xmmc_set_ios,
.get_ro = au1xmmc_card_readonly,
}; };
static int __devinit au1xmmc_probe(struct platform_device *pdev) static int __devinit au1xmmc_probe(struct platform_device *pdev)
...@@ -914,6 +922,9 @@ 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_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
mmc->max_blk_size = 2048;
mmc->max_blk_count = 512;
mmc->ocr_avail = AU1XMMC_OCR; mmc->ocr_avail = AU1XMMC_OCR;
host = mmc_priv(mmc); host = mmc_priv(mmc);
......
...@@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev) ...@@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev)
/* MMC core transfer sizes tunable parameters */ /* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64; mmc->max_hw_segs = 64;
mmc->max_phys_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_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_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
......
...@@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode, mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags); mrq->cmd->arg, mrq->cmd->flags);
WARN_ON(host->card_busy == NULL); WARN_ON(!host->claimed);
mrq->cmd->error = 0; mrq->cmd->error = 0;
mrq->cmd->mrq = mrq; mrq->cmd->mrq = mrq;
if (mrq->data) { 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->cmd->data = mrq->data;
mrq->data->error = 0; mrq->data->error = 0;
mrq->data->mrq = mrq; mrq->data->mrq = mrq;
...@@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries ...@@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{ {
struct mmc_request mrq; struct mmc_request mrq;
BUG_ON(host->card_busy == NULL); BUG_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request)); memset(&mrq, 0, sizeof(struct mmc_request));
...@@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca, ...@@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
int i, err; int i, err;
BUG_ON(host->card_busy == NULL); BUG_ON(!host->claimed);
BUG_ON(retries < 0); BUG_ON(retries < 0);
err = MMC_ERR_INVALID; err = MMC_ERR_INVALID;
...@@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, ...@@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
else else
limit_us = 100000; 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_ns = limit_us * 1000;
data->timeout_clks = 0; data->timeout_clks = 0;
} }
...@@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) ...@@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
while (1) { while (1) {
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
if (host->card_busy == NULL) if (!host->claimed)
break; break;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
schedule(); schedule();
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
host->card_busy = card; host->claimed = 1;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait); remove_wait_queue(&host->wq, &wait);
...@@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host) ...@@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host)
{ {
unsigned long flags; unsigned long flags;
BUG_ON(host->card_busy == NULL); BUG_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
host->card_busy = NULL; host->claimed = 0;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq); wake_up(&host->wq);
...@@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host) ...@@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
mmc_hostname(host), ios->clock, ios->bus_mode, mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd, ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width); ios->bus_width);
host->ops->set_ios(host, ios); host->ops->set_ios(host, ios);
} }
...@@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) ...@@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int err; int err;
struct mmc_command cmd; struct mmc_command cmd;
BUG_ON(host->card_busy == NULL); BUG_ON(!host->claimed);
if (host->card_selected == card) if (host->card_selected == card)
return MMC_ERR_NONE; return MMC_ERR_NONE;
...@@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card) ...@@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card)
if (mmc_card_sd(card)) { if (mmc_card_sd(card)) {
csd_struct = UNSTUFF_BITS(resp, 126, 2); 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 ourselves.
*/
mmc_card_set_blockaddr(card);
csd->tacc_ns = 0; /* Unused */
csd->tacc_clks = 0; /* Unused */
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);
m = UNSTUFF_BITS(resp, 48, 22);
csd->capacity = (1 + m) << 10;
csd->read_blkbits = 9;
csd->read_partial = 0;
csd->write_misalign = 0;
csd->read_misalign = 0;
csd->r2w_factor = 4; /* Unused */
csd->write_blkbits = 9;
csd->write_partial = 0;
break;
default:
printk("%s: unrecognised CSD structure version %d\n", printk("%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct); mmc_hostname(card->host), csd_struct);
mmc_card_set_bad(card); mmc_card_set_bad(card);
return; return;
} }
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);
} else { } else {
/* /*
* We only understand CSD structure v1.1 and v1.2. * We only understand CSD structure v1.1 and v1.2.
...@@ -848,6 +887,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -848,6 +887,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err; return err;
} }
static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
{
struct mmc_command cmd;
int err, sd2;
static const u8 test_pattern = 0xAA;
/*
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
* before SD_APP_OP_COND. This command will harmlessly fail for
* SD 1.0 cards.
*/
cmd.opcode = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err == MMC_ERR_NONE) {
if ((cmd.resp[0] & 0xFF) == test_pattern) {
sd2 = 1;
} else {
sd2 = 0;
err = MMC_ERR_FAILED;
}
} else {
/*
* Treat errors as SD 1.0 card.
*/
sd2 = 0;
err = MMC_ERR_NONE;
}
if (rsd2)
*rsd2 = sd2;
return err;
}
/* /*
* Discover cards by requesting their CID. If this command * Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards * times out, it is not an error; there are no further cards
...@@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_host *host) ...@@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_host *host)
mmc_wait_for_req(host, &mrq); mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
mmc_card_set_dead(card); printk("%s: unable to read EXT_CSD, performance "
"might suffer.\n", mmc_hostname(card->host));
continue; continue;
} }
...@@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host) ...@@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host)
printk("%s: card is mmc v4 but doesn't support " printk("%s: card is mmc v4 but doesn't support "
"any high-speed modes.\n", "any high-speed modes.\n",
mmc_hostname(card->host)); mmc_hostname(card->host));
mmc_card_set_bad(card);
continue; continue;
} }
...@@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host) ...@@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq); mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
mmc_card_set_dead(card); printk("%s: unable to read switch capabilities, "
"performance might suffer.\n",
mmc_hostname(card->host));
continue; continue;
} }
...@@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host) ...@@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq); mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
mmc_card_set_dead(card); (status[16] & 0xF) != 1) {
continue;
}
if ((status[16] & 0xF) != 1) {
printk(KERN_WARNING "%s: Problem switching card " printk(KERN_WARNING "%s: Problem switching card "
"into high-speed mode!\n", "into high-speed mode!\n",
mmc_hostname(host)); mmc_hostname(host));
...@@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *host) ...@@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *host)
mmc_power_up(host); mmc_power_up(host);
mmc_idle_cards(host); mmc_idle_cards(host);
err = mmc_send_if_cond(host, host->ocr_avail, NULL);
if (err != MMC_ERR_NONE) {
return;
}
err = mmc_send_app_op_cond(host, 0, &ocr); err = mmc_send_app_op_cond(host, 0, &ocr);
/* /*
...@@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *host) ...@@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *host)
* all get the idea that they should be ready for CMD2. * all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.) * (My SanDisk card seems to need this.)
*/ */
if (host->mode == MMC_MODE_SD) if (host->mode == MMC_MODE_SD) {
mmc_send_app_op_cond(host, host->ocr, NULL); int err, sd2;
else err = mmc_send_if_cond(host, host->ocr, &sd2);
if (err == MMC_ERR_NONE) {
/*
* If SD_SEND_IF_COND indicates an SD 2.0
* compliant card and we should set bit 30
* of the ocr to indicate that we can handle
* block-addressed SDHC cards.
*/
mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
}
} else {
mmc_send_op_cond(host, host->ocr, NULL); mmc_send_op_cond(host, host->ocr, NULL);
}
mmc_discover_cards(host); mmc_discover_cards(host);
...@@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
*/ */
host->max_hw_segs = 1; host->max_hw_segs = 1;
host->max_phys_segs = 1; host->max_phys_segs = 1;
host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
host->max_seg_size = PAGE_CACHE_SIZE; host->max_seg_size = PAGE_CACHE_SIZE;
host->max_req_size = PAGE_CACHE_SIZE;
host->max_blk_size = 512;
host->max_blk_count = PAGE_CACHE_SIZE / 512;
} }
return host; return host;
......
...@@ -237,13 +237,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -237,13 +237,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.mrq.cmd = &brq.cmd; brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data; brq.mrq.data = &brq.data;
brq.cmd.arg = req->sector << 9; brq.cmd.arg = req->sector;
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 1 << md->block_bits; brq.data.blksz = 1 << md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0; brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
if (brq.data.blocks > card->host->max_blk_count)
brq.data.blocks = card->host->max_blk_count;
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
...@@ -375,9 +379,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -375,9 +379,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock); spin_unlock_irq(&md->lock);
} }
flush_queue:
mmc_card_release_host(card); mmc_card_release_host(card);
flush_queue:
spin_lock_irq(&md->lock); spin_lock_irq(&md->lock);
while (ret) { while (ret) {
ret = end_that_request_chunk(req, 0, ret = end_that_request_chunk(req, 0,
...@@ -494,6 +499,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) ...@@ -494,6 +499,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
struct mmc_command cmd; struct mmc_command cmd;
int err; int err;
/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
if (mmc_card_blockaddr(card))
return 0;
mmc_card_claim_host(card); mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN; cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits; cmd.arg = 1 << md->block_bits;
......
...@@ -147,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock ...@@ -147,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_prep_rq(mq->queue, mmc_prep_request);
blk_queue_bounce_limit(mq->queue, limit); blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_sectors(mq->queue, host->max_sectors); blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size); blk_queue_max_segment_size(mq->queue, host->max_seg_size);
......
...@@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host) ...@@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
memset(card, 0, sizeof(struct mmc_card)); memset(card, 0, sizeof(struct mmc_card));
card->host = host; card->host = host;
device_initialize(&card->dev); device_initialize(&card->dev);
card->dev.parent = mmc_dev(host); card->dev.parent = mmc_classdev(host);
card->dev.bus = &mmc_bus_type; card->dev.bus = &mmc_bus_type;
card->dev.release = mmc_release_card; card->dev.release = mmc_release_card;
} }
......
...@@ -524,15 +524,24 @@ static int mmci_probe(struct amba_device *dev, void *id) ...@@ -524,15 +524,24 @@ static int mmci_probe(struct amba_device *dev, void *id)
/* /*
* Since we only have a 16-bit data length register, we must * Since we only have a 16-bit data length register, we must
* ensure that we don't exceed 2^16-1 bytes in a single request. * ensure that we don't exceed 2^16-1 bytes in a single request.
* Choose 64 (512-byte) sectors as the limit.
*/ */
mmc->max_sectors = 64; mmc->max_req_size = 65535;
/* /*
* Set the maximum segment size. Since we aren't doing DMA * Set the maximum segment size. Since we aren't doing DMA
* (yet) we are only limited by the data length register. * (yet) we are only limited by the data length register.
*/ */
mmc->max_seg_size = mmc->max_sectors << 9; mmc->max_seg_size = mmc->max_req_size;
/*
* Block size can be up to 2048 bytes, but must be a power of two.
*/
mmc->max_blk_size = 2048;
/*
* No limit on the number of blocks transferred.
*/
mmc->max_blk_count = mmc->max_req_size;
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
......
...@@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
*/ */
mmc->max_phys_segs = 32; mmc->max_phys_segs = 32;
mmc->max_hw_segs = 32; mmc->max_hw_segs = 32;
mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */ mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
mmc->max_seg_size = mmc->max_sectors * 512; mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
if (host->power_pin >= 0) { if (host->power_pin >= 0) {
if ((ret = omap_request_gpio(host->power_pin)) != 0) { if ((ret = omap_request_gpio(host->power_pin)) != 0) {
......
...@@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_device *pdev)
*/ */
mmc->max_seg_size = PAGE_SIZE; mmc->max_seg_size = PAGE_SIZE;
/*
* Block length register is 10 bits.
*/
mmc->max_blk_size = 1023;
/*
* Block count register is 16 bits.
*/
mmc->max_blk_count = 65535;
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
host->dma = -1; host->dma = -1;
......
...@@ -37,6 +37,7 @@ static unsigned int debug_quirks = 0; ...@@ -37,6 +37,7 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_FORCE_DMA (1<<1) #define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like some resets when there is no card inserted. */ /* Controller doesn't like some resets when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
static const struct pci_device_id pci_ids[] __devinitdata = { static const struct pci_device_id pci_ids[] __devinitdata = {
{ {
...@@ -65,6 +66,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { ...@@ -65,6 +66,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = SDHCI_QUIRK_FORCE_DMA, .driver_data = SDHCI_QUIRK_FORCE_DMA,
}, },
{
.vendor = PCI_VENDOR_ID_ENE,
.device = PCI_DEVICE_ID_ENE_CB712_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
},
{ /* Generic SD host controller */ { /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
}, },
...@@ -197,15 +206,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host) ...@@ -197,15 +206,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
* * * *
\*****************************************************************************/ \*****************************************************************************/
static inline char* sdhci_kmap_sg(struct sdhci_host* host) static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
{ {
host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ); return page_address(host->cur_sg->page) + host->cur_sg->offset;
return host->mapped_sg + host->cur_sg->offset;
}
static inline void sdhci_kunmap_sg(struct sdhci_host* host)
{
kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
} }
static inline int sdhci_next_sg(struct sdhci_host* host) static inline int sdhci_next_sg(struct sdhci_host* host)
...@@ -240,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host) ...@@ -240,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = 0; chunk_remain = 0;
data = 0; data = 0;
buffer = sdhci_kmap_sg(host) + host->offset; buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) { while (blksize) {
if (chunk_remain == 0) { if (chunk_remain == 0) {
...@@ -264,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host) ...@@ -264,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
} }
if (host->remain == 0) { if (host->remain == 0) {
sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) { if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0); BUG_ON(blksize != 0);
return; return;
} }
buffer = sdhci_kmap_sg(host); buffer = sdhci_sg_to_buffer(host);
} }
} }
sdhci_kunmap_sg(host);
} }
static void sdhci_write_block_pio(struct sdhci_host *host) static void sdhci_write_block_pio(struct sdhci_host *host)
...@@ -290,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host) ...@@ -290,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
data = 0; data = 0;
bytes = 0; bytes = 0;
buffer = sdhci_kmap_sg(host) + host->offset; buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) { while (blksize) {
size = min(host->size, host->remain); size = min(host->size, host->remain);
...@@ -314,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host) ...@@ -314,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
} }
if (host->remain == 0) { if (host->remain == 0) {
sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) { if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0); BUG_ON(blksize != 0);
return; return;
} }
buffer = sdhci_kmap_sg(host); buffer = sdhci_sg_to_buffer(host);
} }
} }
sdhci_kunmap_sg(host);
} }
static void sdhci_transfer_pio(struct sdhci_host *host) static void sdhci_transfer_pio(struct sdhci_host *host)
...@@ -372,7 +369,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) ...@@ -372,7 +369,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
/* Sanity checks */ /* Sanity checks */
BUG_ON(data->blksz * data->blocks > 524288); BUG_ON(data->blksz * data->blocks > 524288);
BUG_ON(data->blksz > host->max_block); BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535); BUG_ON(data->blocks > 65535);
/* timeout in us */ /* timeout in us */
...@@ -674,10 +671,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) ...@@ -674,10 +671,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
if (host->power == power) if (host->power == power)
return; return;
writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); if (power == (unsigned short)-1) {
writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
if (power == (unsigned short)-1)
goto out; goto out;
}
/*
* Spec says that we should clear the power reg before setting
* a new value. Some controllers don't seem to like this though.
*/
if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
pwr = SDHCI_POWER_ON; pwr = SDHCI_POWER_ON;
...@@ -1109,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev) ...@@ -1109,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0); pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev); pci_restore_state(pdev);
pci_enable_device(pdev); ret = pci_enable_device(pdev);
if (ret)
return ret;
for (i = 0;i < chip->num_slots;i++) { for (i = 0;i < chip->num_slots;i++) {
if (!chip->hosts[i]) if (!chip->hosts[i])
...@@ -1274,15 +1280,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) ...@@ -1274,15 +1280,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_TIMEOUT_CLK_UNIT) if (caps & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000; host->timeout_clk *= 1000;
host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
if (host->max_block >= 3) {
printk(KERN_ERR "%s: Invalid maximum block size.\n",
host->slot_descr);
ret = -ENODEV;
goto unmap;
}
host->max_block = 512 << host->max_block;
/* /*
* Set host parameters. * Set host parameters.
*/ */
...@@ -1294,9 +1291,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) ...@@ -1294,9 +1291,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ocr_avail = 0; mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330) if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
else if (caps & SDHCI_CAN_VDD_300) if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
else if (caps & SDHCI_CAN_VDD_180) if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) { if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
...@@ -1326,15 +1323,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) ...@@ -1326,15 +1323,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
/* /*
* Maximum number of sectors in one transfer. Limited by DMA boundary * Maximum number of sectors in one transfer. Limited by DMA boundary
* size (512KiB), which means (512 KiB/512=) 1024 entries. * size (512KiB).
*/ */
mmc->max_sectors = 1024; mmc->max_req_size = 524288;
/* /*
* Maximum segment size. Could be one segment with the maximum number * Maximum segment size. Could be one segment with the maximum number
* of sectors. * of bytes.
*/
mmc->max_seg_size = mmc->max_req_size;
/*
* Maximum block size. This varies from controller to controller and
* is specified in the capabilities register.
*/
mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
if (mmc->max_blk_size >= 3) {
printk(KERN_ERR "%s: Invalid maximum block size.\n",
host->slot_descr);
ret = -ENODEV;
goto unmap;
}
mmc->max_blk_size = 512 << mmc->max_blk_size;
/*
* Maximum block count.
*/ */
mmc->max_seg_size = mmc->max_sectors * 512; mmc->max_blk_count = 65535;
/* /*
* Init tasklets. * Init tasklets.
......
...@@ -174,7 +174,6 @@ struct sdhci_host { ...@@ -174,7 +174,6 @@ struct sdhci_host {
unsigned int max_clk; /* Max possible freq (MHz) */ unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */ unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int max_block; /* Max block size (bytes) */
unsigned int clock; /* Current clock (MHz) */ unsigned int clock; /* Current clock (MHz) */
unsigned short power; /* Current voltage */ unsigned short power; /* Current voltage */
...@@ -184,7 +183,6 @@ struct sdhci_host { ...@@ -184,7 +183,6 @@ struct sdhci_host {
struct mmc_data *data; /* Current data request */ struct mmc_data *data; /* Current data request */
struct scatterlist *cur_sg; /* We're working on this */ struct scatterlist *cur_sg; /* We're working on this */
char *mapped_sg; /* This is where it's mapped */
int num_sg; /* Entries left */ int num_sg; /* Entries left */
int offset; /* Offset into current sg */ int offset; /* Offset into current sg */
int remain; /* Bytes left in current */ int remain; /* Bytes left in current */
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <asm/io.h> #include <asm/io.h>
#define DRIVER_NAME "tifm_sd" #define DRIVER_NAME "tifm_sd"
#define DRIVER_VERSION "0.6" #define DRIVER_VERSION "0.7"
static int no_dma = 0; static int no_dma = 0;
static int fixed_timeout = 0; static int fixed_timeout = 0;
...@@ -79,7 +79,6 @@ typedef enum { ...@@ -79,7 +79,6 @@ typedef enum {
enum { enum {
FIFO_RDY = 0x0001, /* hardware dependent value */ FIFO_RDY = 0x0001, /* hardware dependent value */
HOST_REG = 0x0002,
EJECT = 0x0004, EJECT = 0x0004,
EJECT_DONE = 0x0008, EJECT_DONE = 0x0008,
CARD_BUSY = 0x0010, CARD_BUSY = 0x0010,
...@@ -95,46 +94,53 @@ struct tifm_sd { ...@@ -95,46 +94,53 @@ struct tifm_sd {
card_state_t state; card_state_t state;
unsigned int clk_freq; unsigned int clk_freq;
unsigned int clk_div; unsigned int clk_div;
unsigned long timeout_jiffies; // software timeout - 2 sec unsigned long timeout_jiffies;
struct tasklet_struct finish_tasklet;
struct timer_list timer;
struct mmc_request *req; struct mmc_request *req;
struct work_struct cmd_handler; wait_queue_head_t notify;
struct delayed_work abort_handler;
wait_queue_head_t can_eject;
size_t written_blocks; size_t written_blocks;
char *buffer;
size_t buffer_size; size_t buffer_size;
size_t buffer_pos; size_t buffer_pos;
}; };
static char* tifm_sd_data_buffer(struct mmc_data *data)
{
return page_address(data->sg->page) + data->sg->offset;
}
static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
unsigned int host_status) unsigned int host_status)
{ {
struct mmc_command *cmd = host->req->cmd; struct mmc_command *cmd = host->req->cmd;
unsigned int t_val = 0, cnt = 0; unsigned int t_val = 0, cnt = 0;
char *buffer;
if (host_status & TIFM_MMCSD_BRS) { if (host_status & TIFM_MMCSD_BRS) {
/* in non-dma rx mode BRS fires when fifo is still not empty */ /* in non-dma rx mode BRS fires when fifo is still not empty */
if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) { if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
buffer = tifm_sd_data_buffer(host->req->data);
while (host->buffer_size > host->buffer_pos) { while (host->buffer_size > host->buffer_pos) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA); t_val = readl(sock->addr + SOCK_MMCSD_DATA);
host->buffer[host->buffer_pos++] = t_val & 0xff; buffer[host->buffer_pos++] = t_val & 0xff;
host->buffer[host->buffer_pos++] = buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff; (t_val >> 8) & 0xff;
} }
} }
return 1; return 1;
} else if (host->buffer) { } else if (no_dma) {
buffer = tifm_sd_data_buffer(host->req->data);
if ((cmd->data->flags & MMC_DATA_READ) && if ((cmd->data->flags & MMC_DATA_READ) &&
(host_status & TIFM_MMCSD_AF)) { (host_status & TIFM_MMCSD_AF)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA); t_val = readl(sock->addr + SOCK_MMCSD_DATA);
if (host->buffer_size > host->buffer_pos) { if (host->buffer_size > host->buffer_pos) {
host->buffer[host->buffer_pos++] = buffer[host->buffer_pos++] =
t_val & 0xff; t_val & 0xff;
host->buffer[host->buffer_pos++] = buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff; (t_val >> 8) & 0xff;
} }
} }
...@@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, ...@@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
&& (host_status & TIFM_MMCSD_AE)) { && (host_status & TIFM_MMCSD_AE)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
if (host->buffer_size > host->buffer_pos) { if (host->buffer_size > host->buffer_pos) {
t_val = host->buffer[host->buffer_pos++] & 0x00ff; t_val = buffer[host->buffer_pos++]
t_val |= ((host->buffer[host->buffer_pos++]) << 8) & 0x00ff;
& 0xff00; t_val |= ((buffer[host->buffer_pos++])
<< 8) & 0xff00;
writel(t_val, writel(t_val,
sock->addr + SOCK_MMCSD_DATA); sock->addr + SOCK_MMCSD_DATA);
} }
} }
} }
...@@ -206,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd) ...@@ -206,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
cmd_mask |= TIFM_MMCSD_READ; cmd_mask |= TIFM_MMCSD_READ;
dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
cmd->opcode, cmd->arg, cmd_mask); cmd->opcode, cmd->arg, cmd_mask);
writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
...@@ -239,65 +246,78 @@ static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host, ...@@ -239,65 +246,78 @@ static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
tifm_sd_fetch_resp(cmd, sock); tifm_sd_fetch_resp(cmd, sock);
if (cmd->data) { if (cmd->data) {
host->state = BRS; host->state = BRS;
} else } else {
host->state = READY; host->state = READY;
}
goto change_state; goto change_state;
} }
break; break;
case BRS: case BRS:
if (tifm_sd_transfer_data(sock, host, host_status)) { if (tifm_sd_transfer_data(sock, host, host_status)) {
if (!host->req->stop) { if (cmd->data->flags & MMC_DATA_WRITE) {
if (cmd->data->flags & MMC_DATA_WRITE) { host->state = CARD;
host->state = CARD; } else {
if (no_dma) {
if (host->req->stop) {
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
} else {
host->state = READY;
}
} else { } else {
host->state = host->state = FIFO;
host->buffer ? READY : FIFO;
} }
goto change_state;
} }
tifm_sd_exec(host, host->req->stop); goto change_state;
host->state = SCMD;
} }
break; break;
case SCMD: case SCMD:
if (host_status & TIFM_MMCSD_EOC) { if (host_status & TIFM_MMCSD_EOC) {
tifm_sd_fetch_resp(host->req->stop, sock); tifm_sd_fetch_resp(host->req->stop, sock);
if (cmd->error) { host->state = READY;
host->state = READY;
} else if (cmd->data->flags & MMC_DATA_WRITE) {
host->state = CARD;
} else {
host->state = host->buffer ? READY : FIFO;
}
goto change_state; goto change_state;
} }
break; break;
case CARD: case CARD:
dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
host->written_blocks);
if (!(host->flags & CARD_BUSY) if (!(host->flags & CARD_BUSY)
&& (host->written_blocks == cmd->data->blocks)) { && (host->written_blocks == cmd->data->blocks)) {
host->state = host->buffer ? READY : FIFO; if (no_dma) {
if (host->req->stop) {
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
} else {
host->state = READY;
}
} else {
host->state = FIFO;
}
goto change_state; goto change_state;
} }
break; break;
case FIFO: case FIFO:
if (host->flags & FIFO_RDY) { if (host->flags & FIFO_RDY) {
host->state = READY;
host->flags &= ~FIFO_RDY; host->flags &= ~FIFO_RDY;
if (host->req->stop) {
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
} else {
host->state = READY;
}
goto change_state; goto change_state;
} }
break; break;
case READY: case READY:
queue_work(sock->wq, &host->cmd_handler); tasklet_schedule(&host->finish_tasklet);
return; return;
} }
queue_delayed_work(sock->wq, &host->abort_handler,
host->timeout_jiffies);
} }
/* Called from interrupt handler */ /* Called from interrupt handler */
static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, static void tifm_sd_signal_irq(struct tifm_dev *sock,
unsigned int sock_irq_status) unsigned int sock_irq_status)
{ {
struct tifm_sd *host; struct tifm_sd *host;
unsigned int host_status = 0, fifo_status = 0; unsigned int host_status = 0, fifo_status = 0;
...@@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, ...@@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
spin_lock(&sock->lock); spin_lock(&sock->lock);
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
cancel_delayed_work(&host->abort_handler);
if (sock_irq_status & FIFO_EVENT) { if (sock_irq_status & FIFO_EVENT) {
fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
...@@ -318,19 +337,17 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, ...@@ -318,19 +337,17 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
host_status = readl(sock->addr + SOCK_MMCSD_STATUS); host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
writel(host_status, sock->addr + SOCK_MMCSD_STATUS); writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
if (!(host->flags & HOST_REG))
queue_work(sock->wq, &host->cmd_handler);
if (!host->req) if (!host->req)
goto done; goto done;
if (host_status & TIFM_MMCSD_ERRMASK) { if (host_status & TIFM_MMCSD_ERRMASK) {
if (host_status & TIFM_MMCSD_CERR) if (host_status & TIFM_MMCSD_CERR)
error_code = MMC_ERR_FAILED; error_code = MMC_ERR_FAILED;
else if (host_status & else if (host_status
(TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
error_code = MMC_ERR_TIMEOUT; error_code = MMC_ERR_TIMEOUT;
else if (host_status & else if (host_status
(TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
error_code = MMC_ERR_BADCRC; error_code = MMC_ERR_BADCRC;
writel(TIFM_FIFO_INT_SETALL, writel(TIFM_FIFO_INT_SETALL,
...@@ -340,12 +357,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, ...@@ -340,12 +357,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host->req->stop) { if (host->req->stop) {
if (host->state == SCMD) { if (host->state == SCMD) {
host->req->stop->error = error_code; host->req->stop->error = error_code;
} else if(host->state == BRS) { } else if (host->state == BRS
|| host->state == CARD
|| host->state == FIFO) {
host->req->cmd->error = error_code; host->req->cmd->error = error_code;
tifm_sd_exec(host, host->req->stop); tifm_sd_exec(host, host->req->stop);
queue_delayed_work(sock->wq,
&host->abort_handler,
host->timeout_jiffies);
host->state = SCMD; host->state = SCMD;
goto done; goto done;
} else { } else {
...@@ -359,8 +375,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, ...@@ -359,8 +375,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host_status & TIFM_MMCSD_CB) if (host_status & TIFM_MMCSD_CB)
host->flags |= CARD_BUSY; host->flags |= CARD_BUSY;
if ((host_status & TIFM_MMCSD_EOFB) && if ((host_status & TIFM_MMCSD_EOFB)
(host->flags & CARD_BUSY)) { && (host->flags & CARD_BUSY)) {
host->written_blocks++; host->written_blocks++;
host->flags &= ~CARD_BUSY; host->flags &= ~CARD_BUSY;
} }
...@@ -370,22 +386,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, ...@@ -370,22 +386,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
tifm_sd_process_cmd(sock, host, host_status); tifm_sd_process_cmd(sock, host, host_status);
done: done:
dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
host_status, fifo_status); host_status, fifo_status);
spin_unlock(&sock->lock); spin_unlock(&sock->lock);
return sock_irq_status;
} }
static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
{ {
struct tifm_dev *sock = card->dev; struct tifm_dev *sock = host->dev;
unsigned int dest_cnt; unsigned int dest_cnt;
/* DMA style IO */ /* DMA style IO */
dev_dbg(&sock->dev, "setting dma for %d blocks\n",
cmd->data->blocks);
writel(TIFM_FIFO_INT_SETALL, writel(TIFM_FIFO_INT_SETALL,
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(ilog2(cmd->data->blksz) - 2, writel(ilog2(cmd->data->blksz) - 2,
sock->addr + SOCK_FIFO_PAGE_SIZE); sock->addr + SOCK_FIFO_PAGE_SIZE);
writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
...@@ -399,7 +415,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) ...@@ -399,7 +415,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
if (cmd->data->flags & MMC_DATA_WRITE) { if (cmd->data->flags & MMC_DATA_WRITE) {
writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
sock->addr + SOCK_DMA_CONTROL); sock->addr + SOCK_DMA_CONTROL);
} else { } else {
writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
...@@ -407,7 +423,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) ...@@ -407,7 +423,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
} }
static void tifm_sd_set_data_timeout(struct tifm_sd *host, static void tifm_sd_set_data_timeout(struct tifm_sd *host,
struct mmc_data *data) struct mmc_data *data)
{ {
struct tifm_dev *sock = host->dev; struct tifm_dev *sock = host->dev;
unsigned int data_timeout = data->timeout_clks; unsigned int data_timeout = data->timeout_clks;
...@@ -416,22 +432,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host, ...@@ -416,22 +432,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host,
return; return;
data_timeout += data->timeout_ns / data_timeout += data->timeout_ns /
((1000000000 / host->clk_freq) * host->clk_div); ((1000000000UL / host->clk_freq) * host->clk_div);
data_timeout *= 10; // call it fudge factor for now
if (data_timeout < 0xffff) { if (data_timeout < 0xffff) {
writel((~TIFM_MMCSD_DPE) &
readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
writel((~TIFM_MMCSD_DPE)
& readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
} else { } else {
writel(TIFM_MMCSD_DPE |
readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
data_timeout = (data_timeout >> 10) + 1; data_timeout = (data_timeout >> 10) + 1;
if(data_timeout > 0xffff) if (data_timeout > 0xffff)
data_timeout = 0; /* set to unlimited */ data_timeout = 0; /* set to unlimited */
writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
writel(TIFM_MMCSD_DPE
| readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
} }
} }
...@@ -474,11 +489,10 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -474,11 +489,10 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
} }
host->req = mrq; host->req = mrq;
mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD; host->state = CMD;
queue_delayed_work(sock->wq, &host->abort_handler,
host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL); sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd); tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags); spin_unlock_irqrestore(&sock->lock, flags);
return; return;
...@@ -493,9 +507,9 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -493,9 +507,9 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
mmc_request_done(mmc, mrq); mmc_request_done(mmc, mrq);
} }
static void tifm_sd_end_cmd(struct work_struct *work) static void tifm_sd_end_cmd(unsigned long data)
{ {
struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_sd *host = (struct tifm_sd*)data;
struct tifm_dev *sock = host->dev; struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq; struct mmc_request *mrq;
...@@ -504,6 +518,7 @@ static void tifm_sd_end_cmd(struct work_struct *work) ...@@ -504,6 +518,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags); spin_lock_irqsave(&sock->lock, flags);
del_timer(&host->timer);
mrq = host->req; mrq = host->req;
host->req = NULL; host->req = NULL;
host->state = IDLE; host->state = IDLE;
...@@ -517,8 +532,8 @@ static void tifm_sd_end_cmd(struct work_struct *work) ...@@ -517,8 +532,8 @@ static void tifm_sd_end_cmd(struct work_struct *work)
r_data = mrq->cmd->data; r_data = mrq->cmd->data;
if (r_data) { if (r_data) {
if (r_data->flags & MMC_DATA_WRITE) { if (r_data->flags & MMC_DATA_WRITE) {
r_data->bytes_xfered = host->written_blocks * r_data->bytes_xfered = host->written_blocks
r_data->blksz; * r_data->blksz;
} else { } else {
r_data->bytes_xfered = r_data->blocks - r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
...@@ -532,7 +547,7 @@ static void tifm_sd_end_cmd(struct work_struct *work) ...@@ -532,7 +547,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
} }
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL); sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags); spin_unlock_irqrestore(&sock->lock, flags);
mmc_request_done(mmc, mrq); mmc_request_done(mmc, mrq);
...@@ -544,15 +559,6 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -544,15 +559,6 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
struct tifm_dev *sock = host->dev; struct tifm_dev *sock = host->dev;
unsigned long flags; unsigned long flags;
struct mmc_data *r_data = mrq->cmd->data; struct mmc_data *r_data = mrq->cmd->data;
char *t_buffer = NULL;
if (r_data) {
t_buffer = kmap(r_data->sg->page);
if (!t_buffer) {
printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
goto err_out;
}
}
spin_lock_irqsave(&sock->lock, flags); spin_lock_irqsave(&sock->lock, flags);
if (host->flags & EJECT) { if (host->flags & EJECT) {
...@@ -569,15 +575,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -569,15 +575,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
if (r_data) { if (r_data) {
tifm_sd_set_data_timeout(host, r_data); tifm_sd_set_data_timeout(host, r_data);
host->buffer = t_buffer + r_data->sg->offset; host->buffer_size = mrq->cmd->data->blocks
host->buffer_size = mrq->cmd->data->blocks * * mrq->cmd->data->blksz;
mrq->cmd->data->blksz;
writel(TIFM_MMCSD_BUFINT | writel(TIFM_MMCSD_BUFINT
readl(sock->addr + SOCK_MMCSD_INT_ENABLE), | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
sock->addr + SOCK_MMCSD_INT_ENABLE); sock->addr + SOCK_MMCSD_INT_ENABLE);
writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) | writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
(TIFM_MMCSD_FIFO_SIZE - 1), | (TIFM_MMCSD_FIFO_SIZE - 1),
sock->addr + SOCK_MMCSD_BUFFER_CONFIG); sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
host->written_blocks = 0; host->written_blocks = 0;
...@@ -588,26 +593,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -588,26 +593,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
} }
host->req = mrq; host->req = mrq;
mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD; host->state = CMD;
queue_delayed_work(sock->wq, &host->abort_handler,
host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL); sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd); tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags); spin_unlock_irqrestore(&sock->lock, flags);
return; return;
err_out: err_out:
if (t_buffer)
kunmap(r_data->sg->page);
mrq->cmd->error = MMC_ERR_TIMEOUT; mrq->cmd->error = MMC_ERR_TIMEOUT;
mmc_request_done(mmc, mrq); mmc_request_done(mmc, mrq);
} }
static void tifm_sd_end_cmd_nodma(struct work_struct *work) static void tifm_sd_end_cmd_nodma(unsigned long data)
{ {
struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); struct tifm_sd *host = (struct tifm_sd*)data;
struct tifm_dev *sock = host->dev; struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq; struct mmc_request *mrq;
...@@ -616,6 +617,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) ...@@ -616,6 +617,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags); spin_lock_irqsave(&sock->lock, flags);
del_timer(&host->timer);
mrq = host->req; mrq = host->req;
host->req = NULL; host->req = NULL;
host->state = IDLE; host->state = IDLE;
...@@ -633,8 +635,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) ...@@ -633,8 +635,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
sock->addr + SOCK_MMCSD_INT_ENABLE); sock->addr + SOCK_MMCSD_INT_ENABLE);
if (r_data->flags & MMC_DATA_WRITE) { if (r_data->flags & MMC_DATA_WRITE) {
r_data->bytes_xfered = host->written_blocks * r_data->bytes_xfered = host->written_blocks
r_data->blksz; * r_data->blksz;
} else { } else {
r_data->bytes_xfered = r_data->blocks - r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
...@@ -642,29 +644,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) ...@@ -642,29 +644,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
r_data->bytes_xfered += r_data->blksz - r_data->bytes_xfered += r_data->blksz -
readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
} }
host->buffer = NULL;
host->buffer_pos = 0; host->buffer_pos = 0;
host->buffer_size = 0; host->buffer_size = 0;
} }
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL); sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags); spin_unlock_irqrestore(&sock->lock, flags);
if (r_data)
kunmap(r_data->sg->page);
mmc_request_done(mmc, mrq); mmc_request_done(mmc, mrq);
} }
static void tifm_sd_abort(struct work_struct *work) static void tifm_sd_terminate(struct tifm_sd *host)
{
struct tifm_dev *sock = host->dev;
unsigned long flags;
writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
mmiowb();
spin_lock_irqsave(&sock->lock, flags);
host->flags |= EJECT;
if (host->req) {
writel(TIFM_FIFO_INT_SETALL,
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
tasklet_schedule(&host->finish_tasklet);
}
spin_unlock_irqrestore(&sock->lock, flags);
}
static void tifm_sd_abort(unsigned long data)
{ {
struct tifm_sd *host = struct tifm_sd *host = (struct tifm_sd*)data;
container_of(work, struct tifm_sd, abort_handler.work);
printk(KERN_ERR DRIVER_NAME printk(KERN_ERR DRIVER_NAME
": card failed to respond for a long period of time"); ": card failed to respond for a long period of time");
tifm_sd_terminate(host);
tifm_eject(host->dev); tifm_eject(host->dev);
} }
...@@ -683,9 +700,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -683,9 +700,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
sock->addr + SOCK_MMCSD_CONFIG); sock->addr + SOCK_MMCSD_CONFIG);
} else { } else {
writel((~TIFM_MMCSD_4BBUS) & writel((~TIFM_MMCSD_4BBUS)
readl(sock->addr + SOCK_MMCSD_CONFIG), & readl(sock->addr + SOCK_MMCSD_CONFIG),
sock->addr + SOCK_MMCSD_CONFIG); sock->addr + SOCK_MMCSD_CONFIG);
} }
if (ios->clock) { if (ios->clock) {
...@@ -704,23 +721,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -704,23 +721,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if ((20000000 / clk_div1) > (24000000 / clk_div2)) { if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
host->clk_freq = 20000000; host->clk_freq = 20000000;
host->clk_div = clk_div1; host->clk_div = clk_div1;
writel((~TIFM_CTRL_FAST_CLK) & writel((~TIFM_CTRL_FAST_CLK)
readl(sock->addr + SOCK_CONTROL), & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL); sock->addr + SOCK_CONTROL);
} else { } else {
host->clk_freq = 24000000; host->clk_freq = 24000000;
host->clk_div = clk_div2; host->clk_div = clk_div2;
writel(TIFM_CTRL_FAST_CLK | writel(TIFM_CTRL_FAST_CLK
readl(sock->addr + SOCK_CONTROL), | readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL); sock->addr + SOCK_CONTROL);
} }
} else { } else {
host->clk_div = 0; host->clk_div = 0;
} }
host->clk_div &= TIFM_MMCSD_CLKMASK; host->clk_div &= TIFM_MMCSD_CLKMASK;
writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) & writel(host->clk_div
readl(sock->addr + SOCK_MMCSD_CONFIG)), | ((~TIFM_MMCSD_CLKMASK)
sock->addr + SOCK_MMCSD_CONFIG); & readl(sock->addr + SOCK_MMCSD_CONFIG)),
sock->addr + SOCK_MMCSD_CONFIG);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
host->flags |= OPENDRAIN; host->flags |= OPENDRAIN;
...@@ -734,7 +752,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -734,7 +752,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
// allow removal. // allow removal.
if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
host->flags |= EJECT_DONE; host->flags |= EJECT_DONE;
wake_up_all(&host->can_eject); wake_up_all(&host->notify);
} }
spin_unlock_irqrestore(&sock->lock, flags); spin_unlock_irqrestore(&sock->lock, flags);
...@@ -762,20 +780,67 @@ static struct mmc_host_ops tifm_sd_ops = { ...@@ -762,20 +780,67 @@ static struct mmc_host_ops tifm_sd_ops = {
.get_ro = tifm_sd_ro .get_ro = tifm_sd_ro
}; };
static void tifm_sd_register_host(struct work_struct *work) static int tifm_sd_initialize_host(struct tifm_sd *host)
{ {
struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); int rc;
unsigned int host_status = 0;
struct tifm_dev *sock = host->dev; struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock);
unsigned long flags;
spin_lock_irqsave(&sock->lock, flags); writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
host->flags |= HOST_REG; mmiowb();
PREPARE_WORK(&host->cmd_handler, host->clk_div = 61;
no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd); host->clk_freq = 20000000;
spin_unlock_irqrestore(&sock->lock, flags); writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
dev_dbg(&sock->dev, "adding host\n"); writel(host->clk_div | TIFM_MMCSD_POWER,
mmc_add_host(mmc); sock->addr + SOCK_MMCSD_CONFIG);
/* wait up to 0.51 sec for reset */
for (rc = 2; rc <= 256; rc <<= 1) {
if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
rc = 0;
break;
}
msleep(rc);
}
if (rc) {
printk(KERN_ERR DRIVER_NAME
": controller failed to reset\n");
return -ENODEV;
}
writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
writel(host->clk_div | TIFM_MMCSD_POWER,
sock->addr + SOCK_MMCSD_CONFIG);
writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
// command timeout fixed to 64 clocks for now
writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
/* INAB should take much less than reset */
for (rc = 1; rc <= 16; rc <<= 1) {
host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
if (!(host_status & TIFM_MMCSD_ERRMASK)
&& (host_status & TIFM_MMCSD_EOC)) {
rc = 0;
break;
}
msleep(rc);
}
if (rc) {
printk(KERN_ERR DRIVER_NAME
": card not ready - probe failed on initialization\n");
return -ENODEV;
}
writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
sock->addr + SOCK_MMCSD_INT_ENABLE);
mmiowb();
return 0;
} }
static int tifm_sd_probe(struct tifm_dev *sock) static int tifm_sd_probe(struct tifm_dev *sock)
...@@ -784,8 +849,8 @@ static int tifm_sd_probe(struct tifm_dev *sock) ...@@ -784,8 +849,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
struct tifm_sd *host; struct tifm_sd *host;
int rc = -EIO; int rc = -EIO;
if (!(TIFM_SOCK_STATE_OCCUPIED & if (!(TIFM_SOCK_STATE_OCCUPIED
readl(sock->addr + SOCK_PRESENT_STATE))) { & readl(sock->addr + SOCK_PRESENT_STATE))) {
printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n"); printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
return rc; return rc;
} }
...@@ -795,109 +860,99 @@ static int tifm_sd_probe(struct tifm_dev *sock) ...@@ -795,109 +860,99 @@ static int tifm_sd_probe(struct tifm_dev *sock)
return -ENOMEM; return -ENOMEM;
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->dev = sock;
host->clk_div = 61;
init_waitqueue_head(&host->can_eject);
INIT_WORK(&host->cmd_handler, tifm_sd_register_host);
INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort);
tifm_set_drvdata(sock, mmc); tifm_set_drvdata(sock, mmc);
sock->signal_irq = tifm_sd_signal_irq; host->dev = sock;
host->clk_freq = 20000000;
host->timeout_jiffies = msecs_to_jiffies(1000); host->timeout_jiffies = msecs_to_jiffies(1000);
init_waitqueue_head(&host->notify);
tasklet_init(&host->finish_tasklet,
no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
(unsigned long)host);
setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
mmc->ops = &tifm_sd_ops; mmc->ops = &tifm_sd_ops;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_4_BIT_DATA; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
mmc->f_min = 20000000 / 60; mmc->f_min = 20000000 / 60;
mmc->f_max = 24000000; mmc->f_max = 24000000;
mmc->max_hw_segs = 1; mmc->max_hw_segs = 1;
mmc->max_phys_segs = 1; mmc->max_phys_segs = 1;
mmc->max_sectors = 127; // limited by DMA counter - it's safer to stick with
mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length // block counter has 11 bits though
mmc->max_blk_count = 256;
writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); // 2k maximum hw block length
writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); mmc->max_blk_size = 2048;
writel(host->clk_div | TIFM_MMCSD_POWER, mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
sock->addr + SOCK_MMCSD_CONFIG); mmc->max_seg_size = mmc->max_req_size;
sock->signal_irq = tifm_sd_signal_irq;
rc = tifm_sd_initialize_host(host);
for (rc = 0; rc < 50; rc++) { if (!rc)
/* Wait for reset ack */ rc = mmc_add_host(mmc);
if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { if (rc)
rc = 0; goto out_free_mmc;
break;
}
msleep(10);
}
if (rc) { return 0;
printk(KERN_ERR DRIVER_NAME out_free_mmc:
": card not ready - probe failed\n"); mmc_free_host(mmc);
mmc_free_host(mmc); return rc;
return -ENODEV; }
}
writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); static void tifm_sd_remove(struct tifm_dev *sock)
writel(host->clk_div | TIFM_MMCSD_POWER, {
sock->addr + SOCK_MMCSD_CONFIG); struct mmc_host *mmc = tifm_get_drvdata(sock);
writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); struct tifm_sd *host = mmc_priv(mmc);
writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
sock->addr + SOCK_MMCSD_INT_ENABLE);
writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now del_timer_sync(&host->timer);
writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); tifm_sd_terminate(host);
writel(host->clk_div | TIFM_MMCSD_POWER, wait_event_timeout(host->notify, host->flags & EJECT_DONE,
sock->addr + SOCK_MMCSD_CONFIG); host->timeout_jiffies);
tasklet_kill(&host->finish_tasklet);
mmc_remove_host(mmc);
queue_delayed_work(sock->wq, &host->abort_handler, /* The meaning of the bit majority in this constant is unknown. */
host->timeout_jiffies); writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
return 0; tifm_set_drvdata(sock, NULL);
mmc_free_host(mmc);
} }
static int tifm_sd_host_is_down(struct tifm_dev *sock) #ifdef CONFIG_PM
static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
{ {
struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_host *mmc = tifm_get_drvdata(sock);
struct tifm_sd *host = mmc_priv(mmc); int rc;
unsigned long flags;
int rc = 0;
spin_lock_irqsave(&sock->lock, flags); rc = mmc_suspend_host(mmc, state);
rc = (host->flags & EJECT_DONE); /* The meaning of the bit majority in this constant is unknown. */
spin_unlock_irqrestore(&sock->lock, flags); writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
return rc; return rc;
} }
static void tifm_sd_remove(struct tifm_dev *sock) static int tifm_sd_resume(struct tifm_dev *sock)
{ {
struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_host *mmc = tifm_get_drvdata(sock);
struct tifm_sd *host = mmc_priv(mmc); struct tifm_sd *host = mmc_priv(mmc);
unsigned long flags;
spin_lock_irqsave(&sock->lock, flags); if (sock->media_id != FM_SD
host->flags |= EJECT; || tifm_sd_initialize_host(host)) {
if (host->req) tifm_eject(sock);
queue_work(sock->wq, &host->cmd_handler); return 0;
spin_unlock_irqrestore(&sock->lock, flags); } else {
wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock), return mmc_resume_host(mmc);
host->timeout_jiffies); }
}
if (host->flags & HOST_REG) #else
mmc_remove_host(mmc);
/* The meaning of the bit majority in this constant is unknown. */ #define tifm_sd_suspend NULL
writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), #define tifm_sd_resume NULL
sock->addr + SOCK_CONTROL);
writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
writel(TIFM_FIFO_INT_SETALL,
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
tifm_set_drvdata(sock, NULL); #endif /* CONFIG_PM */
mmc_free_host(mmc);
}
static tifm_media_id tifm_sd_id_tbl[] = { static tifm_media_id tifm_sd_id_tbl[] = {
FM_SD, 0 FM_SD, 0
...@@ -910,7 +965,9 @@ static struct tifm_driver tifm_sd_driver = { ...@@ -910,7 +965,9 @@ static struct tifm_driver tifm_sd_driver = {
}, },
.id_table = tifm_sd_id_tbl, .id_table = tifm_sd_id_tbl,
.probe = tifm_sd_probe, .probe = tifm_sd_probe,
.remove = tifm_sd_remove .remove = tifm_sd_remove,
.suspend = tifm_sd_suspend,
.resume = tifm_sd_resume
}; };
static int __init tifm_sd_init(void) static int __init tifm_sd_init(void)
......
/* /*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver * linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
* *
* Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved. * Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -272,16 +272,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host) ...@@ -272,16 +272,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
return host->num_sg; return host->num_sg;
} }
static inline char *wbsd_kmap_sg(struct wbsd_host *host) static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
{ {
host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) + return page_address(host->cur_sg->page) + host->cur_sg->offset;
host->cur_sg->offset;
return host->mapped_sg;
}
static inline void wbsd_kunmap_sg(struct wbsd_host *host)
{
kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
} }
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
...@@ -302,12 +295,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) ...@@ -302,12 +295,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much. * we do not transfer too much.
*/ */
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length) if (size < sg[i].length)
memcpy(dmabuf, sgbuf, size); memcpy(dmabuf, sgbuf, size);
else else
memcpy(dmabuf, sgbuf, sg[i].length); memcpy(dmabuf, sgbuf, sg[i].length);
kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
dmabuf += sg[i].length; dmabuf += sg[i].length;
if (size < sg[i].length) if (size < sg[i].length)
...@@ -347,7 +339,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) ...@@ -347,7 +339,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much. * we do not transfer too much.
*/ */
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length) if (size < sg[i].length)
memcpy(sgbuf, dmabuf, size); memcpy(sgbuf, dmabuf, size);
else else
...@@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) ...@@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size) if (data->bytes_xfered == host->size)
return; return;
buffer = wbsd_kmap_sg(host) + host->offset; buffer = wbsd_sg_to_buffer(host) + host->offset;
/* /*
* Drain the fifo. This has a tendency to loop longer * Drain the fifo. This has a tendency to loop longer
...@@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host) ...@@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/* /*
* Transfer done? * Transfer done?
*/ */
if (data->bytes_xfered == host->size) { if (data->bytes_xfered == host->size)
wbsd_kunmap_sg(host);
return; return;
}
/* /*
* End of scatter list entry? * End of scatter list entry?
*/ */
if (host->remain == 0) { if (host->remain == 0) {
wbsd_kunmap_sg(host);
/* /*
* Get next entry. Check if last. * Get next entry. Check if last.
*/ */
...@@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host) ...@@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
return; return;
} }
buffer = wbsd_kmap_sg(host); buffer = wbsd_sg_to_buffer(host);
} }
} }
} }
wbsd_kunmap_sg(host);
/* /*
* This is a very dirty hack to solve a * This is a very dirty hack to solve a
* hardware problem. The chip doesn't trigger * hardware problem. The chip doesn't trigger
...@@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) ...@@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size) if (data->bytes_xfered == host->size)
return; return;
buffer = wbsd_kmap_sg(host) + host->offset; buffer = wbsd_sg_to_buffer(host) + host->offset;
/* /*
* Fill the fifo. This has a tendency to loop longer * Fill the fifo. This has a tendency to loop longer
...@@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host) ...@@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
/* /*
* Transfer done? * Transfer done?
*/ */
if (data->bytes_xfered == host->size) { if (data->bytes_xfered == host->size)
wbsd_kunmap_sg(host);
return; return;
}
/* /*
* End of scatter list entry? * End of scatter list entry?
*/ */
if (host->remain == 0) { if (host->remain == 0) {
wbsd_kunmap_sg(host);
/* /*
* Get next entry. Check if last. * Get next entry. Check if last.
*/ */
...@@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host) ...@@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
return; return;
} }
buffer = wbsd_kmap_sg(host); buffer = wbsd_sg_to_buffer(host);
} }
} }
} }
wbsd_kunmap_sg(host);
/* /*
* The controller stops sending interrupts for * The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we * 'FIFO empty' under certain conditions. So we
...@@ -909,6 +889,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -909,6 +889,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
* transfered. * transfered.
*/ */
if (cmd->data && (cmd->error == MMC_ERR_NONE)) { if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
* The hardware is so delightfully stupid that it has a list
* of "data" commands. If a command isn't on this list, it'll
* just go back to the idle state and won't send any data
* interrupts.
*/
switch (cmd->opcode) {
case 11:
case 17:
case 18:
case 20:
case 24:
case 25:
case 26:
case 27:
case 30:
case 42:
case 56:
break;
/* ACMDs. We don't keep track of state, so we just treat them
* like any other command. */
case 51:
break;
default:
#ifdef CONFIG_MMC_DEBUG
printk(KERN_WARNING "%s: Data command %d is not "
"supported by this controller.\n",
mmc_hostname(host->mmc), cmd->opcode);
#endif
cmd->data->error = MMC_ERR_INVALID;
if (cmd->data->stop)
wbsd_send_command(host, cmd->data->stop);
goto done;
};
/* /*
* Dirty fix for hardware bug. * Dirty fix for hardware bug.
*/ */
...@@ -1343,16 +1362,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) ...@@ -1343,16 +1362,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->max_phys_segs = 128; mmc->max_phys_segs = 128;
/* /*
* Maximum number of sectors in one transfer. Also limited by 64kB * Maximum request size. Also limited by 64KiB buffer.
* buffer.
*/ */
mmc->max_sectors = 128; mmc->max_req_size = 65536;
/* /*
* Maximum segment size. Could be one segment with the maximum number * Maximum segment size. Could be one segment with the maximum number
* of segments. * of bytes.
*/
mmc->max_seg_size = mmc->max_req_size;
/*
* Maximum block size. We have 12 bits (= 4095) but have to subtract
* space for CRC. So the maximum is 4095 - 4*2 = 4087.
*/
mmc->max_blk_size = 4087;
/*
* Maximum block count. There is no real limit so the maximum
* request size will be the only restriction.
*/ */
mmc->max_seg_size = mmc->max_sectors * 512; mmc->max_blk_count = mmc->max_req_size;
dev_set_drvdata(dev, mmc); dev_set_drvdata(dev, mmc);
......
...@@ -154,7 +154,6 @@ struct wbsd_host ...@@ -154,7 +154,6 @@ struct wbsd_host
struct scatterlist* cur_sg; /* Current SG entry */ struct scatterlist* cur_sg; /* Current SG entry */
unsigned int num_sg; /* Number of entries left */ unsigned int num_sg; /* Number of entries left */
void* mapped_sg; /* vaddr of mapped sg */
unsigned int offset; /* Offset into current entry */ unsigned int offset; /* Offset into current entry */
unsigned int remain; /* Data left in curren entry */ unsigned int remain; /* Data left in curren entry */
......
...@@ -71,6 +71,7 @@ struct mmc_card { ...@@ -71,6 +71,7 @@ struct mmc_card {
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */
#define MMC_STATE_READONLY (1<<4) /* card is read-only */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */
#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */ #define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */
#define MMC_STATE_BLOCKADDR (1<<6) /* card uses block-addressing */
u32 raw_cid[4]; /* raw card CID */ u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */ u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */ u32 raw_scr[2]; /* raw card SCR */
...@@ -87,6 +88,7 @@ struct mmc_card { ...@@ -87,6 +88,7 @@ struct mmc_card {
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) #define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
...@@ -94,6 +96,7 @@ struct mmc_card { ...@@ -94,6 +96,7 @@ struct mmc_card {
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) #define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED) #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) ((c)->dev.bus_id) #define mmc_card_id(c) ((c)->dev.bus_id)
......
...@@ -92,8 +92,10 @@ struct mmc_host { ...@@ -92,8 +92,10 @@ struct mmc_host {
unsigned int max_seg_size; /* see blk_queue_max_segment_size */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */ unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */
unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */ unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */
unsigned short max_sectors; /* see blk_queue_max_sectors */
unsigned short unused; unsigned short unused;
unsigned int max_req_size; /* maximum number of bytes in one req */
unsigned int max_blk_size; /* maximum size of one mmc block */
unsigned int max_blk_count; /* maximum number of blocks in one req */
/* private data */ /* private data */
struct mmc_ios ios; /* current io bus settings */ struct mmc_ios ios; /* current io bus settings */
...@@ -106,8 +108,9 @@ struct mmc_host { ...@@ -106,8 +108,9 @@ struct mmc_host {
struct list_head cards; /* devices attached to this host */ struct list_head cards; /* devices attached to this host */
wait_queue_head_t wq; wait_queue_head_t wq;
spinlock_t lock; /* card_busy lock */ spinlock_t lock; /* claimed lock */
struct mmc_card *card_busy; /* the MMC card claiming host */ unsigned int claimed:1; /* host exclusively claimed */
struct mmc_card *card_selected; /* the selected MMC card */ struct mmc_card *card_selected; /* the selected MMC card */
struct delayed_work detect; struct delayed_work detect;
...@@ -126,6 +129,7 @@ static inline void *mmc_priv(struct mmc_host *host) ...@@ -126,6 +129,7 @@ static inline void *mmc_priv(struct mmc_host *host)
} }
#define mmc_dev(x) ((x)->parent) #define mmc_dev(x) ((x)->parent)
#define mmc_classdev(x) (&(x)->class_dev)
#define mmc_hostname(x) ((x)->class_dev.bus_id) #define mmc_hostname(x) ((x)->class_dev.bus_id)
extern int mmc_suspend_host(struct mmc_host *, pm_message_t); extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
......
...@@ -43,6 +43,7 @@ struct mmc_command { ...@@ -43,6 +43,7 @@ struct mmc_command {
#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R3 (MMC_RSP_PRESENT)
#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
......
...@@ -79,9 +79,12 @@ ...@@ -79,9 +79,12 @@
#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ #define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* SD commands type argument response */ /* SD commands type argument response */
/* class 8 */ /* class 0 */
/* This is basically the same command as for MMC with some quirks. */ /* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
/* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ #define SD_SWITCH 6 /* adtc [31:0] See below R1 */
/* Application commands */ /* Application commands */
...@@ -114,6 +117,14 @@ ...@@ -114,6 +117,14 @@
* [3:0] Function group 1 * [3:0] Function group 1
*/ */
/*
* SD_SEND_IF_COND argument format:
*
* [31:12] Reserved (0)
* [11:8] Host Voltage Supply Flags
* [7:0] Check Pattern (0xAA)
*/
/* /*
MMC status in R1 MMC status in R1
Type Type
......
...@@ -735,9 +735,11 @@ ...@@ -735,9 +735,11 @@
#define PCI_DEVICE_ID_TI_TVP4020 0x3d07 #define PCI_DEVICE_ID_TI_TVP4020 0x3d07
#define PCI_DEVICE_ID_TI_4450 0x8011 #define PCI_DEVICE_ID_TI_4450 0x8011
#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 #define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033
#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034 #define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034
#define PCI_DEVICE_ID_TI_X515 0x8036 #define PCI_DEVICE_ID_TI_X515 0x8036
#define PCI_DEVICE_ID_TI_XX12 0x8039 #define PCI_DEVICE_ID_TI_XX12 0x8039
#define PCI_DEVICE_ID_TI_XX12_FM 0x803b
#define PCI_DEVICE_ID_TI_1130 0xac12 #define PCI_DEVICE_ID_TI_1130 0xac12
#define PCI_DEVICE_ID_TI_1031 0xac13 #define PCI_DEVICE_ID_TI_1031 0xac13
#define PCI_DEVICE_ID_TI_1131 0xac15 #define PCI_DEVICE_ID_TI_1131 0xac15
...@@ -765,6 +767,7 @@ ...@@ -765,6 +767,7 @@
#define PCI_DEVICE_ID_TI_1510 0xac56 #define PCI_DEVICE_ID_TI_1510 0xac56
#define PCI_DEVICE_ID_TI_X620 0xac8d #define PCI_DEVICE_ID_TI_X620 0xac8d
#define PCI_DEVICE_ID_TI_X420 0xac8e #define PCI_DEVICE_ID_TI_X420 0xac8e
#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f
#define PCI_VENDOR_ID_SONY 0x104d #define PCI_VENDOR_ID_SONY 0x104d
...@@ -1971,6 +1974,7 @@ ...@@ -1971,6 +1974,7 @@
#define PCI_DEVICE_ID_TOPIC_TP560 0x0000 #define PCI_DEVICE_ID_TOPIC_TP560 0x0000
#define PCI_VENDOR_ID_ENE 0x1524 #define PCI_VENDOR_ID_ENE 0x1524
#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550
#define PCI_DEVICE_ID_ENE_1211 0x1211 #define PCI_DEVICE_ID_ENE_1211 0x1211
#define PCI_DEVICE_ID_ENE_1225 0x1225 #define PCI_DEVICE_ID_ENE_1225 0x1225
#define PCI_DEVICE_ID_ENE_1410 0x1410 #define PCI_DEVICE_ID_ENE_1410 0x1410
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/scatterlist.h> #include <linux/kthread.h>
/* Host registers (relative to pci base address): */ /* Host registers (relative to pci base address): */
enum { enum {
...@@ -62,11 +62,10 @@ enum { ...@@ -62,11 +62,10 @@ enum {
#define TIFM_IRQ_ENABLE 0x80000000 #define TIFM_IRQ_ENABLE 0x80000000
#define TIFM_IRQ_SOCKMASK 0x00000001 #define TIFM_IRQ_SOCKMASK(x) (x)
#define TIFM_IRQ_CARDMASK 0x00000100 #define TIFM_IRQ_CARDMASK(x) ((x) << 8)
#define TIFM_IRQ_FIFOMASK 0x00010000 #define TIFM_IRQ_FIFOMASK(x) ((x) << 16)
#define TIFM_IRQ_SETALL 0xffffffff #define TIFM_IRQ_SETALL 0xffffffff
#define TIFM_IRQ_SETALLSOCK 0x0000000f
#define TIFM_CTRL_LED 0x00000040 #define TIFM_CTRL_LED 0x00000040
#define TIFM_CTRL_FAST_CLK 0x00000100 #define TIFM_CTRL_FAST_CLK 0x00000100
...@@ -89,10 +88,9 @@ struct tifm_dev { ...@@ -89,10 +88,9 @@ struct tifm_dev {
char __iomem *addr; char __iomem *addr;
spinlock_t lock; spinlock_t lock;
tifm_media_id media_id; tifm_media_id media_id;
char wq_name[KOBJ_NAME_LEN]; unsigned int socket_id;
struct workqueue_struct *wq;
unsigned int (*signal_irq)(struct tifm_dev *sock, void (*signal_irq)(struct tifm_dev *sock,
unsigned int sock_irq_status); unsigned int sock_irq_status);
struct tifm_driver *drv; struct tifm_driver *drv;
...@@ -103,24 +101,23 @@ struct tifm_driver { ...@@ -103,24 +101,23 @@ struct tifm_driver {
tifm_media_id *id_table; tifm_media_id *id_table;
int (*probe)(struct tifm_dev *dev); int (*probe)(struct tifm_dev *dev);
void (*remove)(struct tifm_dev *dev); void (*remove)(struct tifm_dev *dev);
int (*suspend)(struct tifm_dev *dev,
pm_message_t state);
int (*resume)(struct tifm_dev *dev);
struct device_driver driver; struct device_driver driver;
}; };
struct tifm_adapter { struct tifm_adapter {
char __iomem *addr; char __iomem *addr;
unsigned int irq_status;
unsigned int insert_mask;
unsigned int remove_mask;
spinlock_t lock; spinlock_t lock;
unsigned int irq_status;
unsigned int socket_change_set;
wait_queue_head_t change_set_notify;
unsigned int id; unsigned int id;
unsigned int max_sockets; unsigned int num_sockets;
char wq_name[KOBJ_NAME_LEN];
unsigned int inhibit_new_cards;
struct workqueue_struct *wq;
struct work_struct media_inserter;
struct work_struct media_remover;
struct tifm_dev **sockets; struct tifm_dev **sockets;
struct task_struct *media_switcher;
struct class_device cdev; struct class_device cdev;
struct device *dev; struct device *dev;
...@@ -130,9 +127,9 @@ struct tifm_adapter { ...@@ -130,9 +127,9 @@ struct tifm_adapter {
struct tifm_adapter *tifm_alloc_adapter(void); struct tifm_adapter *tifm_alloc_adapter(void);
void tifm_free_device(struct device *dev); void tifm_free_device(struct device *dev);
void tifm_free_adapter(struct tifm_adapter *fm); void tifm_free_adapter(struct tifm_adapter *fm);
int tifm_add_adapter(struct tifm_adapter *fm); int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
void tifm_remove_adapter(struct tifm_adapter *fm); void tifm_remove_adapter(struct tifm_adapter *fm);
struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id); struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
int tifm_register_driver(struct tifm_driver *drv); int tifm_register_driver(struct tifm_driver *drv);
void tifm_unregister_driver(struct tifm_driver *drv); void tifm_unregister_driver(struct tifm_driver *drv);
void tifm_eject(struct tifm_dev *sock); void tifm_eject(struct tifm_dev *sock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment