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
  ...
This commit is contained in:
Linus Torvalds 2007-02-06 14:54:54 -08:00
Родитель 02aedd69e2 f9d429a2e5
Коммит 2442d31099
24 изменённых файлов: 895 добавлений и 583 удалений

Просмотреть файл

@ -3647,7 +3647,7 @@ S: Maintained
W83L51xD SD/MMC CARD INTERFACE DRIVER
P: Pierre Ossman
M: drzeus-wbsd@drzeus.cx
L: wbsd-devel@list.drzeus.cx
L: linux-kernel@vger.kernel.org
W: http://projects.drzeus.cx/wbsd
S: Maintained

Просмотреть файл

@ -11,66 +11,25 @@
#include <linux/tifm.h>
#include <linux/dma-mapping.h>
#include <linux/freezer.h>
#define DRIVER_NAME "tifm_7xx1"
#define DRIVER_VERSION "0.6"
#define DRIVER_VERSION "0.7"
static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
{
int cnt;
unsigned long flags;
spin_lock_irqsave(&fm->lock, flags);
if (!fm->inhibit_new_cards) {
for (cnt = 0; cnt < fm->max_sockets; cnt++) {
if (fm->sockets[cnt] == sock) {
fm->remove_mask |= (1 << cnt);
queue_work(fm->wq, &fm->media_remover);
break;
}
}
}
fm->socket_change_set |= 1 << sock->socket_id;
wake_up_all(&fm->change_set_notify);
spin_unlock_irqrestore(&fm->lock, flags);
}
static void tifm_7xx1_remove_media(struct work_struct *work)
{
struct tifm_adapter *fm =
container_of(work, struct tifm_adapter, media_remover);
unsigned long flags;
int cnt;
struct tifm_dev *sock;
if (!class_device_get(&fm->cdev))
return;
spin_lock_irqsave(&fm->lock, flags);
for (cnt = 0; cnt < fm->max_sockets; cnt++) {
if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
printk(KERN_INFO DRIVER_NAME
": demand removing card from socket %d\n", cnt);
sock = fm->sockets[cnt];
fm->sockets[cnt] = NULL;
fm->remove_mask &= ~(1 << cnt);
writel(0x0e00, sock->addr + SOCK_CONTROL);
writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
fm->addr + FM_SET_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&fm->lock, flags);
device_unregister(&sock->dev);
spin_lock_irqsave(&fm->lock, flags);
}
}
spin_unlock_irqrestore(&fm->lock, flags);
class_device_put(&fm->cdev);
}
static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
{
struct tifm_adapter *fm = dev_id;
struct tifm_dev *sock;
unsigned int irq_status;
unsigned int sock_irq_status, cnt;
@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
if (irq_status & TIFM_IRQ_ENABLE) {
writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
for (cnt = 0; cnt < fm->max_sockets; cnt++) {
sock_irq_status = (irq_status >> cnt) &
(TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
for (cnt = 0; cnt < fm->num_sockets; cnt++) {
sock = fm->sockets[cnt];
sock_irq_status = (irq_status >> cnt)
& (TIFM_IRQ_FIFOMASK(1)
| TIFM_IRQ_CARDMASK(1));
if (fm->sockets[cnt]) {
if (sock_irq_status &&
fm->sockets[cnt]->signal_irq)
sock_irq_status = fm->sockets[cnt]->
signal_irq(fm->sockets[cnt],
sock_irq_status);
if (irq_status & (1 << cnt))
fm->remove_mask |= 1 << cnt;
} else {
if (irq_status & (1 << cnt))
fm->insert_mask |= 1 << cnt;
}
if (sock && sock_irq_status)
sock->signal_irq(sock, sock_irq_status);
}
fm->socket_change_set |= irq_status
& ((1 << fm->num_sockets) - 1);
}
writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
if (!fm->inhibit_new_cards) {
if (!fm->remove_mask && !fm->insert_mask) {
writel(TIFM_IRQ_ENABLE,
fm->addr + FM_SET_INTERRUPT_ENABLE);
} else {
queue_work(fm->wq, &fm->media_remover);
queue_work(fm->wq, &fm->media_inserter);
}
}
if (!fm->socket_change_set)
writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
else
wake_up_all(&fm->change_set_notify);
spin_unlock(&fm->lock);
return IRQ_HANDLED;
}
static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
int is_x2)
{
unsigned int s_state;
int cnt;
@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
writel(0x0e00, sock_addr + SOCK_CONTROL);
for (cnt = 0; cnt < 100; cnt++) {
if (!(TIFM_SOCK_STATE_POWERED &
readl(sock_addr + SOCK_PRESENT_STATE)))
if (!(TIFM_SOCK_STATE_POWERED
& readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
}
for (cnt = 0; cnt < 100; cnt++) {
if ((TIFM_SOCK_STATE_POWERED &
readl(sock_addr + SOCK_PRESENT_STATE)))
if ((TIFM_SOCK_STATE_POWERED
& readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
return base_addr + ((sock_num + 1) << 10);
}
static void tifm_7xx1_insert_media(struct work_struct *work)
static int tifm_7xx1_switch_media(void *data)
{
struct tifm_adapter *fm =
container_of(work, struct tifm_adapter, media_inserter);
struct tifm_adapter *fm = data;
unsigned long flags;
tifm_media_id media_id;
char *card_name = "xx";
int cnt, ok_to_register;
unsigned int insert_mask;
struct tifm_dev *new_sock = NULL;
int cnt, rc;
struct tifm_dev *sock;
unsigned int socket_change_set;
if (!class_device_get(&fm->cdev))
return;
spin_lock_irqsave(&fm->lock, flags);
insert_mask = fm->insert_mask;
fm->insert_mask = 0;
if (fm->inhibit_new_cards) {
while (1) {
rc = wait_event_interruptible(fm->change_set_notify,
fm->socket_change_set);
if (rc == -ERESTARTSYS)
try_to_freeze();
spin_lock_irqsave(&fm->lock, flags);
socket_change_set = fm->socket_change_set;
fm->socket_change_set = 0;
dev_dbg(fm->dev, "checking media set %x\n",
socket_change_set);
if (kthread_should_stop())
socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
class_device_put(&fm->cdev);
return;
}
spin_unlock_irqrestore(&fm->lock, flags);
for (cnt = 0; cnt < fm->max_sockets; cnt++) {
if (!(insert_mask & (1 << cnt)))
if (!socket_change_set)
continue;
media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
fm->max_sockets == 2);
if (media_id) {
ok_to_register = 0;
new_sock = tifm_alloc_device(fm, cnt);
if (new_sock) {
new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
cnt);
new_sock->media_id = media_id;
switch (media_id) {
case 1:
card_name = "xd";
break;
case 2:
card_name = "ms";
break;
case 3:
card_name = "sd";
break;
default:
break;
}
snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
"tifm_%s%u:%u", card_name, fm->id, cnt);
spin_lock_irqsave(&fm->lock, flags);
for (cnt = 0; cnt < fm->num_sockets; cnt++) {
if (!(socket_change_set & (1 << cnt)))
continue;
sock = fm->sockets[cnt];
if (sock) {
printk(KERN_INFO DRIVER_NAME
": %s card detected in socket %d\n",
card_name, cnt);
spin_lock_irqsave(&fm->lock, flags);
if (!fm->sockets[cnt]) {
fm->sockets[cnt] = new_sock;
ok_to_register = 1;
}
": demand removing card from socket %d\n",
cnt);
fm->sockets[cnt] = NULL;
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);
device_unregister(&sock->dev);
spin_lock_irqsave(&fm->lock, flags);
writel(0x0e00,
tifm_7xx1_sock_addr(fm->addr, cnt)
+ SOCK_CONTROL);
}
if (kthread_should_stop())
continue;
spin_unlock_irqrestore(&fm->lock, flags);
media_id = tifm_7xx1_toggle_sock_power(
tifm_7xx1_sock_addr(fm->addr, cnt),
fm->num_sockets == 2);
if (media_id) {
sock = tifm_alloc_device(fm);
if (sock) {
sock->addr = tifm_7xx1_sock_addr(fm->addr,
cnt);
sock->media_id = media_id;
sock->socket_id = cnt;
switch (media_id) {
case 1:
card_name = "xd";
break;
case 2:
card_name = "ms";
break;
case 3:
card_name = "sd";
break;
default:
tifm_free_device(&sock->dev);
spin_lock_irqsave(&fm->lock, flags);
continue;
}
snprintf(sock->dev.bus_id, BUS_ID_SIZE,
"tifm_%s%u:%u", card_name,
fm->id, cnt);
printk(KERN_INFO DRIVER_NAME
": %s card detected in socket %d\n",
card_name, cnt);
if (!device_register(&sock->dev)) {
spin_lock_irqsave(&fm->lock, flags);
if (!fm->sockets[cnt]) {
fm->sockets[cnt] = sock;
sock = NULL;
}
spin_unlock_irqrestore(&fm->lock, flags);
}
if (sock)
tifm_free_device(&sock->dev);
}
spin_lock_irqsave(&fm->lock, flags);
}
}
writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
fm->addr + FM_SET_INTERRUPT_ENABLE);
}
writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
class_device_put(&fm->cdev);
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);
}
}
}
return 0;
}
#ifdef CONFIG_PM
static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
unsigned long flags;
dev_dbg(&dev->dev, "suspending host\n");
spin_lock_irqsave(&fm->lock, flags);
fm->inhibit_new_cards = 1;
fm->remove_mask = 0xf;
fm->insert_mask = 0;
writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&fm->lock, flags);
flush_workqueue(fm->wq);
tifm_7xx1_remove_media(&fm->media_remover);
pci_set_power_state(dev, PCI_D3hot);
pci_disable_device(dev);
pci_save_state(dev);
pci_save_state(dev);
pci_enable_wake(dev, pci_choose_state(dev, state), 0);
pci_disable_device(dev);
pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
static int tifm_7xx1_resume(struct pci_dev *dev)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
int cnt, rc;
unsigned long flags;
tifm_media_id new_ids[fm->num_sockets];
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
pci_enable_device(dev);
pci_set_power_state(dev, PCI_D0);
pci_set_master(dev);
rc = pci_enable_device(dev);
if (rc)
return rc;
pci_set_master(dev);
dev_dbg(&dev->dev, "resuming host\n");
for (cnt = 0; cnt < fm->num_sockets; cnt++)
new_ids[cnt] = tifm_7xx1_toggle_sock_power(
tifm_7xx1_sock_addr(fm->addr, cnt),
fm->num_sockets == 2);
spin_lock_irqsave(&fm->lock, flags);
fm->socket_change_set = 0;
for (cnt = 0; cnt < fm->num_sockets; cnt++) {
if (fm->sockets[cnt]) {
if (fm->sockets[cnt]->media_id == new_ids[cnt])
fm->socket_change_set |= 1 << cnt;
fm->sockets[cnt]->media_id = new_ids[cnt];
}
}
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
fm->addr + FM_SET_INTERRUPT_ENABLE);
if (!fm->socket_change_set) {
spin_unlock_irqrestore(&fm->lock, flags);
return 0;
} else {
fm->socket_change_set = 0;
spin_unlock_irqrestore(&fm->lock, flags);
}
wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
spin_lock_irqsave(&fm->lock, flags);
fm->inhibit_new_cards = 0;
writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
fm->addr + FM_SET_INTERRUPT_ENABLE);
fm->insert_mask = 0xf;
writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
| TIFM_IRQ_CARDMASK(fm->socket_change_set),
fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
| TIFM_IRQ_CARDMASK(fm->socket_change_set),
fm->addr + FM_SET_INTERRUPT_ENABLE);
writel(TIFM_IRQ_ENABLE,
fm->addr + FM_SET_INTERRUPT_ENABLE);
fm->socket_change_set = 0;
spin_unlock_irqrestore(&fm->lock, flags);
return 0;
}
#else
#define tifm_7xx1_suspend NULL
#define tifm_7xx1_resume NULL
#endif /* CONFIG_PM */
static int tifm_7xx1_probe(struct pci_dev *dev,
const struct pci_device_id *dev_id)
const struct pci_device_id *dev_id)
{
struct tifm_adapter *fm;
int pci_dev_busy = 0;
@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
}
fm->dev = &dev->dev;
fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
GFP_KERNEL);
fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
? 4 : 2;
fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
GFP_KERNEL);
if (!fm->sockets)
goto err_out_free;
INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media);
INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
fm->eject = tifm_7xx1_eject;
pci_set_drvdata(dev, fm);
fm->addr = ioremap(pci_resource_start(dev, 0),
pci_resource_len(dev, 0));
pci_resource_len(dev, 0));
if (!fm->addr)
goto err_out_free;
@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
if (rc)
goto err_out_unmap;
rc = tifm_add_adapter(fm);
init_waitqueue_head(&fm->change_set_notify);
rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
if (rc)
goto err_out_irq;
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
fm->addr + FM_SET_INTERRUPT_ENABLE);
fm->insert_mask = 0xf;
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
fm->addr + FM_SET_INTERRUPT_ENABLE);
wake_up_process(fm->media_switcher);
return 0;
err_out_irq:
@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
struct tifm_adapter *fm = pci_get_drvdata(dev);
unsigned long flags;
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
mmiowb();
free_irq(dev->irq, fm);
spin_lock_irqsave(&fm->lock, flags);
fm->inhibit_new_cards = 1;
fm->remove_mask = 0xf;
fm->insert_mask = 0;
writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
fm->socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
flush_workqueue(fm->wq);
tifm_7xx1_remove_media(&fm->media_remover);
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
free_irq(dev->irq, fm);
kthread_stop(fm->media_switcher);
tifm_remove_adapter(fm);
@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
}
static struct pci_device_id tifm_7xx1_pci_tbl [] = {
{ PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
0 }, /* xx21 - the one I have */
{ PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
0 }, /* xx12 - should be also supported */
{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 0 },
{ }
};

Просмотреть файл

@ -14,7 +14,7 @@
#include <linux/idr.h>
#define DRIVER_NAME "tifm_core"
#define DRIVER_VERSION "0.6"
#define DRIVER_VERSION "0.7"
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);
@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp,
return 0;
}
#ifdef CONFIG_PM
static int tifm_device_suspend(struct device *dev, pm_message_t state)
{
struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
struct tifm_driver *drv = fm_dev->drv;
if (drv && drv->suspend)
return drv->suspend(fm_dev, state);
return 0;
}
static int tifm_device_resume(struct device *dev)
{
struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
struct tifm_driver *drv = fm_dev->drv;
if (drv && drv->resume)
return drv->resume(fm_dev);
return 0;
}
#else
#define tifm_device_suspend NULL
#define tifm_device_resume NULL
#endif /* CONFIG_PM */
static struct bus_type tifm_bus_type = {
.name = "tifm",
.match = tifm_match,
.uevent = tifm_uevent,
.suspend = tifm_device_suspend,
.resume = tifm_device_resume
};
static void tifm_free(struct class_device *cdev)
@ -71,8 +102,6 @@ static void tifm_free(struct class_device *cdev)
struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
kfree(fm->sockets);
if (fm->wq)
destroy_workqueue(fm->wq);
kfree(fm);
}
@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
}
EXPORT_SYMBOL(tifm_free_adapter);
int tifm_add_adapter(struct tifm_adapter *fm)
int tifm_add_adapter(struct tifm_adapter *fm,
int (*mediathreadfn)(void *data))
{
int rc;
@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
spin_unlock(&tifm_adapter_lock);
if (!rc) {
snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
fm->media_switcher = kthread_create(mediathreadfn,
fm, "tifm/%u", fm->id);
fm->wq = create_singlethread_workqueue(fm->wq_name);
if (fm->wq)
if (!IS_ERR(fm->media_switcher))
return class_device_add(&fm->cdev);
spin_lock(&tifm_adapter_lock);
@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter);
void tifm_free_device(struct device *dev)
{
struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
if (fm_dev->wq)
destroy_workqueue(fm_dev->wq);
kfree(fm_dev);
}
EXPORT_SYMBOL(tifm_free_device);
struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
static void tifm_dummy_signal_irq(struct tifm_dev *sock,
unsigned int sock_irq_status)
{
return;
}
struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
{
struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
if (dev) {
spin_lock_init(&dev->lock);
snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
dev->wq = create_singlethread_workqueue(dev->wq_name);
if (!dev->wq) {
kfree(dev);
return NULL;
}
dev->dev.parent = fm->dev;
dev->dev.bus = &tifm_bus_type;
dev->dev.release = tifm_free_device;
dev->signal_irq = tifm_dummy_signal_irq;
}
return dev;
}
@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev)
struct tifm_driver *drv = fm_dev->drv;
if (drv) {
fm_dev->signal_irq = tifm_dummy_signal_irq;
if (drv->remove)
drv->remove(fm_dev);
fm_dev->drv = NULL;
@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv)
drv->driver.bus = &tifm_bus_type;
drv->driver.probe = tifm_device_probe;
drv->driver.remove = tifm_device_remove;
drv->driver.suspend = tifm_device_suspend;
drv->driver.resume = tifm_device_resume;
return driver_register(&drv->driver);
}

Просмотреть файл

@ -823,6 +823,9 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_BYTEBLOCK;
mmc->max_blk_size = 4095;
mmc->max_blk_count = mmc->max_req_size;
host = mmc_priv(mmc);
host->mmc = mmc;
host->buffer = NULL;

Просмотреть файл

@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
? 1 : 0;
}
static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
static int au1xmmc_card_readonly(struct mmc_host *mmc)
{
struct au1xmmc_host *host = mmc_priv(mmc);
return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
? 1 : 0;
}
@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE:
break;
case MMC_RSP_R1:
mmccmd |= SD_CMD_RT_1;
break;
@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
case MMC_RSP_R3:
mmccmd |= SD_CMD_RT_3;
break;
default:
printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
mmc_resp_type(cmd));
return MMC_ERR_INVALID;
}
switch(cmd->opcode) {
@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request,
.set_ios = au1xmmc_set_ios,
.get_ro = au1xmmc_card_readonly,
};
static int __devinit au1xmmc_probe(struct platform_device *pdev)
@ -914,6 +922,9 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
mmc->max_blk_size = 2048;
mmc->max_blk_count = 512;
mmc->ocr_avail = AU1XMMC_OCR;
host = mmc_priv(mmc);

Просмотреть файл

@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev)
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */
mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */
mmc->max_blk_size = 2048;
mmc->max_blk_count = 65535;
host = mmc_priv(mmc);
host->mmc = mmc;

Просмотреть файл

@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
WARN_ON(host->card_busy == NULL);
WARN_ON(!host->claimed);
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
BUG_ON(mrq->data->blksz > host->max_blk_size);
BUG_ON(mrq->data->blocks > host->max_blk_count);
BUG_ON(mrq->data->blocks * mrq->data->blksz >
host->max_req_size);
mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
BUG_ON(host->card_busy == NULL);
BUG_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
int i, err;
BUG_ON(host->card_busy == NULL);
BUG_ON(!host->claimed);
BUG_ON(retries < 0);
err = MMC_ERR_INVALID;
@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
else
limit_us = 100000;
if (timeout_us > limit_us) {
/*
* SDHC cards always use these fixed values.
*/
if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0;
}
@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (host->card_busy == NULL)
if (!host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
host->card_busy = card;
host->claimed = 1;
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
BUG_ON(host->card_busy == NULL);
BUG_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
host->card_busy = NULL;
host->claimed = 0;
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width);
host->ops->set_ios(host, ios);
}
@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int err;
struct mmc_command cmd;
BUG_ON(host->card_busy == NULL);
BUG_ON(!host->claimed);
if (host->card_selected == card)
return MMC_ERR_NONE;
@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card)
if (mmc_card_sd(card)) {
csd_struct = UNSTUFF_BITS(resp, 126, 2);
if (csd_struct != 0) {
switch (csd_struct) {
case 0:
m = UNSTUFF_BITS(resp, 115, 4);
e = UNSTUFF_BITS(resp, 112, 3);
csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
m = UNSTUFF_BITS(resp, 99, 4);
e = UNSTUFF_BITS(resp, 96, 3);
csd->max_dtr = tran_exp[e] * tran_mant[m];
csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
e = UNSTUFF_BITS(resp, 47, 3);
m = UNSTUFF_BITS(resp, 62, 12);
csd->capacity = (1 + m) << (e + 2);
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
break;
case 1:
/*
* This is a block-addressed SDHC card. Most
* interesting fields are unused and have fixed
* values. To avoid getting tripped by buggy cards,
* we assume those fixed values 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",
mmc_hostname(card->host), csd_struct);
mmc_card_set_bad(card);
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 {
/*
* 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)
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
* 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)
mmc_wait_for_req(host, &mrq);
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;
}
@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host)
printk("%s: card is mmc v4 but doesn't support "
"any high-speed modes.\n",
mmc_hostname(card->host));
mmc_card_set_bad(card);
continue;
}
@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
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;
}
@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
mmc_card_set_dead(card);
continue;
}
if ((status[16] & 0xF) != 1) {
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
(status[16] & 0xF) != 1) {
printk(KERN_WARNING "%s: Problem switching card "
"into high-speed mode!\n",
mmc_hostname(host));
@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *host)
mmc_power_up(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);
/*
@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *host)
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
if (host->mode == MMC_MODE_SD)
mmc_send_app_op_cond(host, host->ocr, NULL);
else
if (host->mode == MMC_MODE_SD) {
int err, sd2;
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_discover_cards(host);
@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
*/
host->max_hw_segs = 1;
host->max_phys_segs = 1;
host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
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;

Просмотреть файл

@ -237,13 +237,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.mrq.cmd = &brq.cmd;
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.data.blksz = 1 << md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
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);
@ -375,9 +379,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
flush_queue:
mmc_card_release_host(card);
flush_queue:
spin_lock_irq(&md->lock);
while (ret) {
ret = end_that_request_chunk(req, 0,
@ -494,6 +499,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
struct mmc_command cmd;
int err;
/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
if (mmc_card_blockaddr(card))
return 0;
mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN;
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
blk_queue_prep_rq(mq->queue, mmc_prep_request);
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_hw_segments(mq->queue, host->max_hw_segs);
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)
memset(card, 0, sizeof(struct mmc_card));
card->host = host;
device_initialize(&card->dev);
card->dev.parent = mmc_dev(host);
card->dev.parent = mmc_classdev(host);
card->dev.bus = &mmc_bus_type;
card->dev.release = mmc_release_card;
}

Просмотреть файл

@ -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
* 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
* (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);

Просмотреть файл

@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
*/
mmc->max_phys_segs = 32;
mmc->max_hw_segs = 32;
mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */
mmc->max_seg_size = mmc->max_sectors * 512;
mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
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 ((ret = omap_request_gpio(host->power_pin)) != 0) {

Просмотреть файл

@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_device *pdev)
*/
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 = mmc;
host->dma = -1;

Просмотреть файл

@ -37,6 +37,7 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like some resets when there is no card inserted. */
#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 = {
{
@ -65,6 +66,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.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 */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@ -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 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);
return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline int sdhci_next_sg(struct sdhci_host* host)
@ -240,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = 0;
data = 0;
buffer = sdhci_kmap_sg(host) + host->offset;
buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
if (chunk_remain == 0) {
@ -264,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
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)
@ -290,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
data = 0;
bytes = 0;
buffer = sdhci_kmap_sg(host) + host->offset;
buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
size = min(host->size, host->remain);
@ -314,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
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)
@ -372,7 +369,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
/* Sanity checks */
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);
/* timeout in us */
@ -674,10 +671,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
if (host->power == power)
return;
writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
if (power == (unsigned short)-1)
if (power == (unsigned short)-1) {
writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
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;
@ -1109,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
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++) {
if (!chip->hosts[i])
@ -1274,15 +1280,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
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.
*/
@ -1294,9 +1291,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
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;
else if (caps & SDHCI_CAN_VDD_180)
if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
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)
/*
* 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
* of sectors.
* of bytes.
*/
mmc->max_seg_size = mmc->max_sectors * 512;
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_blk_count = 65535;
/*
* Init tasklets.

Просмотреть файл

@ -174,7 +174,6 @@ struct sdhci_host {
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int max_block; /* Max block size (bytes) */
unsigned int clock; /* Current clock (MHz) */
unsigned short power; /* Current voltage */
@ -184,7 +183,6 @@ struct sdhci_host {
struct mmc_data *data; /* Current data request */
struct scatterlist *cur_sg; /* We're working on this */
char *mapped_sg; /* This is where it's mapped */
int num_sg; /* Entries left */
int offset; /* Offset into current sg */
int remain; /* Bytes left in current */

Просмотреть файл

@ -17,7 +17,7 @@
#include <asm/io.h>
#define DRIVER_NAME "tifm_sd"
#define DRIVER_VERSION "0.6"
#define DRIVER_VERSION "0.7"
static int no_dma = 0;
static int fixed_timeout = 0;
@ -79,7 +79,6 @@ typedef enum {
enum {
FIFO_RDY = 0x0001, /* hardware dependent value */
HOST_REG = 0x0002,
EJECT = 0x0004,
EJECT_DONE = 0x0008,
CARD_BUSY = 0x0010,
@ -95,46 +94,53 @@ struct tifm_sd {
card_state_t state;
unsigned int clk_freq;
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 work_struct cmd_handler;
struct delayed_work abort_handler;
wait_queue_head_t can_eject;
wait_queue_head_t notify;
size_t written_blocks;
char *buffer;
size_t buffer_size;
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,
unsigned int host_status)
unsigned int host_status)
{
struct mmc_command *cmd = host->req->cmd;
unsigned int t_val = 0, cnt = 0;
char *buffer;
if (host_status & TIFM_MMCSD_BRS) {
/* 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) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA);
host->buffer[host->buffer_pos++] = t_val & 0xff;
host->buffer[host->buffer_pos++] =
buffer[host->buffer_pos++] = t_val & 0xff;
buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
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) &&
(host_status & TIFM_MMCSD_AF)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA);
if (host->buffer_size > host->buffer_pos) {
host->buffer[host->buffer_pos++] =
buffer[host->buffer_pos++] =
t_val & 0xff;
host->buffer[host->buffer_pos++] =
buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
&& (host_status & TIFM_MMCSD_AE)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
if (host->buffer_size > host->buffer_pos) {
t_val = host->buffer[host->buffer_pos++] & 0x00ff;
t_val |= ((host->buffer[host->buffer_pos++]) << 8)
& 0xff00;
t_val = buffer[host->buffer_pos++]
& 0x00ff;
t_val |= ((buffer[host->buffer_pos++])
<< 8) & 0xff00;
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)
cmd_mask |= TIFM_MMCSD_READ;
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 & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
@ -239,65 +246,78 @@ change_state:
tifm_sd_fetch_resp(cmd, sock);
if (cmd->data) {
host->state = BRS;
} else
} else {
host->state = READY;
}
goto change_state;
}
break;
case BRS:
if (tifm_sd_transfer_data(sock, host, host_status)) {
if (!host->req->stop) {
if (cmd->data->flags & MMC_DATA_WRITE) {
host->state = CARD;
if (cmd->data->flags & MMC_DATA_WRITE) {
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 {
host->state =
host->buffer ? READY : FIFO;
host->state = FIFO;
}
goto change_state;
}
tifm_sd_exec(host, host->req->stop);
host->state = SCMD;
goto change_state;
}
break;
case SCMD:
if (host_status & TIFM_MMCSD_EOC) {
tifm_sd_fetch_resp(host->req->stop, sock);
if (cmd->error) {
host->state = READY;
} else if (cmd->data->flags & MMC_DATA_WRITE) {
host->state = CARD;
} else {
host->state = host->buffer ? READY : FIFO;
}
host->state = READY;
goto change_state;
}
break;
case CARD:
dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
host->written_blocks);
if (!(host->flags & CARD_BUSY)
&& (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;
}
break;
case FIFO:
if (host->flags & FIFO_RDY) {
host->state = READY;
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;
}
break;
case READY:
queue_work(sock->wq, &host->cmd_handler);
tasklet_schedule(&host->finish_tasklet);
return;
}
queue_delayed_work(sock->wq, &host->abort_handler,
host->timeout_jiffies);
}
/* Called from interrupt handler */
static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
unsigned int sock_irq_status)
static void tifm_sd_signal_irq(struct tifm_dev *sock,
unsigned int sock_irq_status)
{
struct tifm_sd *host;
unsigned int host_status = 0, fifo_status = 0;
@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
spin_lock(&sock->lock);
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
cancel_delayed_work(&host->abort_handler);
if (sock_irq_status & FIFO_EVENT) {
fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
@ -318,19 +337,17 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
host_status = readl(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)
goto done;
if (host_status & TIFM_MMCSD_ERRMASK) {
if (host_status & TIFM_MMCSD_CERR)
error_code = MMC_ERR_FAILED;
else if (host_status &
(TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
else if (host_status
& (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
error_code = MMC_ERR_TIMEOUT;
else if (host_status &
(TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
else if (host_status
& (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
error_code = MMC_ERR_BADCRC;
writel(TIFM_FIFO_INT_SETALL,
@ -340,12 +357,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host->req->stop) {
if (host->state == SCMD) {
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;
tifm_sd_exec(host, host->req->stop);
queue_delayed_work(sock->wq,
&host->abort_handler,
host->timeout_jiffies);
host->state = SCMD;
goto done;
} else {
@ -359,8 +375,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host_status & TIFM_MMCSD_CB)
host->flags |= CARD_BUSY;
if ((host_status & TIFM_MMCSD_EOFB) &&
(host->flags & CARD_BUSY)) {
if ((host_status & TIFM_MMCSD_EOFB)
&& (host->flags & CARD_BUSY)) {
host->written_blocks++;
host->flags &= ~CARD_BUSY;
}
@ -370,22 +386,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
tifm_sd_process_cmd(sock, host, host_status);
done:
dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
host_status, fifo_status);
host_status, fifo_status);
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;
/* DMA style IO */
dev_dbg(&sock->dev, "setting dma for %d blocks\n",
cmd->data->blocks);
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,
sock->addr + SOCK_FIFO_PAGE_SIZE);
sock->addr + SOCK_FIFO_PAGE_SIZE);
writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
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)
if (cmd->data->flags & MMC_DATA_WRITE) {
writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
sock->addr + SOCK_DMA_CONTROL);
sock->addr + SOCK_DMA_CONTROL);
} else {
writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
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)
}
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;
unsigned int data_timeout = data->timeout_clks;
@ -416,22 +432,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host,
return;
data_timeout += data->timeout_ns /
((1000000000 / host->clk_freq) * host->clk_div);
data_timeout *= 10; // call it fudge factor for now
((1000000000UL / host->clk_freq) * host->clk_div);
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((~TIFM_MMCSD_DPE)
& readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
} 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;
if(data_timeout > 0xffff)
if (data_timeout > 0xffff)
data_timeout = 0; /* set to unlimited */
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)
}
host->req = mrq;
mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD;
queue_delayed_work(sock->wq, &host->abort_handler,
host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags);
return;
@ -493,9 +507,9 @@ err_out:
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 mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
@ -504,6 +518,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@ -517,8 +532,8 @@ static void tifm_sd_end_cmd(struct work_struct *work)
r_data = mrq->cmd->data;
if (r_data) {
if (r_data->flags & MMC_DATA_WRITE) {
r_data->bytes_xfered = host->written_blocks *
r_data->blksz;
r_data->bytes_xfered = host->written_blocks
* r_data->blksz;
} else {
r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@ -532,7 +547,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
}
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags);
mmc_request_done(mmc, 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;
unsigned long flags;
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);
if (host->flags & EJECT) {
@ -569,15 +575,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
if (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 *
mrq->cmd->data->blksz;
host->buffer_size = mrq->cmd->data->blocks
* mrq->cmd->data->blksz;
writel(TIFM_MMCSD_BUFINT |
readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
writel(TIFM_MMCSD_BUFINT
| readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
sock->addr + SOCK_MMCSD_INT_ENABLE);
writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
(TIFM_MMCSD_FIFO_SIZE - 1),
writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
| (TIFM_MMCSD_FIFO_SIZE - 1),
sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
host->written_blocks = 0;
@ -588,26 +593,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->req = mrq;
mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD;
queue_delayed_work(sock->wq, &host->abort_handler,
host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags);
return;
err_out:
if (t_buffer)
kunmap(r_data->sg->page);
mrq->cmd->error = MMC_ERR_TIMEOUT;
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 mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
@ -616,6 +617,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@ -633,8 +635,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
sock->addr + SOCK_MMCSD_INT_ENABLE);
if (r_data->flags & MMC_DATA_WRITE) {
r_data->bytes_xfered = host->written_blocks *
r_data->blksz;
r_data->bytes_xfered = host->written_blocks
* r_data->blksz;
} else {
r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@ -642,29 +644,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
r_data->bytes_xfered += r_data->blksz -
readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
}
host->buffer = NULL;
host->buffer_pos = 0;
host->buffer_size = 0;
}
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags);
if (r_data)
kunmap(r_data->sg->page);
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_sd *host =
container_of(work, struct tifm_sd, abort_handler.work);
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*)data;
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);
}
@ -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),
sock->addr + SOCK_MMCSD_CONFIG);
} else {
writel((~TIFM_MMCSD_4BBUS) &
readl(sock->addr + SOCK_MMCSD_CONFIG),
sock->addr + SOCK_MMCSD_CONFIG);
writel((~TIFM_MMCSD_4BBUS)
& readl(sock->addr + SOCK_MMCSD_CONFIG),
sock->addr + SOCK_MMCSD_CONFIG);
}
if (ios->clock) {
@ -704,23 +721,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
host->clk_freq = 20000000;
host->clk_div = clk_div1;
writel((~TIFM_CTRL_FAST_CLK) &
readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
writel((~TIFM_CTRL_FAST_CLK)
& readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
} else {
host->clk_freq = 24000000;
host->clk_div = clk_div2;
writel(TIFM_CTRL_FAST_CLK |
readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
writel(TIFM_CTRL_FAST_CLK
| readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
}
} else {
host->clk_div = 0;
}
host->clk_div &= TIFM_MMCSD_CLKMASK;
writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
readl(sock->addr + SOCK_MMCSD_CONFIG)),
sock->addr + SOCK_MMCSD_CONFIG);
writel(host->clk_div
| ((~TIFM_MMCSD_CLKMASK)
& readl(sock->addr + SOCK_MMCSD_CONFIG)),
sock->addr + SOCK_MMCSD_CONFIG);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
host->flags |= OPENDRAIN;
@ -734,7 +752,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
// allow removal.
if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
host->flags |= EJECT_DONE;
wake_up_all(&host->can_eject);
wake_up_all(&host->notify);
}
spin_unlock_irqrestore(&sock->lock, flags);
@ -762,20 +780,67 @@ static struct mmc_host_ops tifm_sd_ops = {
.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 mmc_host *mmc = tifm_get_drvdata(sock);
unsigned long flags;
spin_lock_irqsave(&sock->lock, flags);
host->flags |= HOST_REG;
PREPARE_WORK(&host->cmd_handler,
no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd);
spin_unlock_irqrestore(&sock->lock, flags);
dev_dbg(&sock->dev, "adding host\n");
mmc_add_host(mmc);
writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
mmiowb();
host->clk_div = 61;
host->clk_freq = 20000000;
writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
writel(host->clk_div | TIFM_MMCSD_POWER,
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)
@ -784,8 +849,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
struct tifm_sd *host;
int rc = -EIO;
if (!(TIFM_SOCK_STATE_OCCUPIED &
readl(sock->addr + SOCK_PRESENT_STATE))) {
if (!(TIFM_SOCK_STATE_OCCUPIED
& readl(sock->addr + SOCK_PRESENT_STATE))) {
printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
return rc;
}
@ -795,78 +860,42 @@ static int tifm_sd_probe(struct tifm_dev *sock)
return -ENOMEM;
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);
sock->signal_irq = tifm_sd_signal_irq;
host->clk_freq = 20000000;
host->dev = sock;
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;
mmc->ops = &tifm_sd_ops;
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_max = 24000000;
mmc->max_hw_segs = 1;
mmc->max_phys_segs = 1;
mmc->max_sectors = 127;
mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
// limited by DMA counter - it's safer to stick with
// block counter has 11 bits though
mmc->max_blk_count = 256;
// 2k maximum hw block length
mmc->max_blk_size = 2048;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
sock->signal_irq = tifm_sd_signal_irq;
rc = tifm_sd_initialize_host(host);
writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
writel(host->clk_div | TIFM_MMCSD_POWER,
sock->addr + SOCK_MMCSD_CONFIG);
for (rc = 0; rc < 50; rc++) {
/* Wait for reset ack */
if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
rc = 0;
break;
}
msleep(10);
}
if (rc) {
printk(KERN_ERR DRIVER_NAME
": card not ready - probe failed\n");
mmc_free_host(mmc);
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);
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
writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
writel(host->clk_div | TIFM_MMCSD_POWER,
sock->addr + SOCK_MMCSD_CONFIG);
queue_delayed_work(sock->wq, &host->abort_handler,
host->timeout_jiffies);
if (!rc)
rc = mmc_add_host(mmc);
if (rc)
goto out_free_mmc;
return 0;
}
static int tifm_sd_host_is_down(struct tifm_dev *sock)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct tifm_sd *host = mmc_priv(mmc);
unsigned long flags;
int rc = 0;
spin_lock_irqsave(&sock->lock, flags);
rc = (host->flags & EJECT_DONE);
spin_unlock_irqrestore(&sock->lock, flags);
out_free_mmc:
mmc_free_host(mmc);
return rc;
}
@ -874,31 +903,57 @@ static void tifm_sd_remove(struct tifm_dev *sock)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct tifm_sd *host = mmc_priv(mmc);
unsigned long flags;
spin_lock_irqsave(&sock->lock, flags);
host->flags |= EJECT;
if (host->req)
queue_work(sock->wq, &host->cmd_handler);
spin_unlock_irqrestore(&sock->lock, flags);
wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
host->timeout_jiffies);
if (host->flags & HOST_REG)
mmc_remove_host(mmc);
del_timer_sync(&host->timer);
tifm_sd_terminate(host);
wait_event_timeout(host->notify, host->flags & EJECT_DONE,
host->timeout_jiffies);
tasklet_kill(&host->finish_tasklet);
mmc_remove_host(mmc);
/* The meaning of the bit majority in this constant is unknown. */
writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
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);
sock->addr + SOCK_CONTROL);
tifm_set_drvdata(sock, NULL);
mmc_free_host(mmc);
}
#ifdef CONFIG_PM
static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
int rc;
rc = mmc_suspend_host(mmc, state);
/* The meaning of the bit majority in this constant is unknown. */
writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
sock->addr + SOCK_CONTROL);
return rc;
}
static int tifm_sd_resume(struct tifm_dev *sock)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct tifm_sd *host = mmc_priv(mmc);
if (sock->media_id != FM_SD
|| tifm_sd_initialize_host(host)) {
tifm_eject(sock);
return 0;
} else {
return mmc_resume_host(mmc);
}
}
#else
#define tifm_sd_suspend NULL
#define tifm_sd_resume NULL
#endif /* CONFIG_PM */
static tifm_media_id tifm_sd_id_tbl[] = {
FM_SD, 0
};
@ -910,7 +965,9 @@ static struct tifm_driver tifm_sd_driver = {
},
.id_table = tifm_sd_id_tbl,
.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)

Просмотреть файл

@ -1,7 +1,7 @@
/*
* 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
* 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)
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) +
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);
return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
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.
*/
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)
memcpy(dmabuf, sgbuf, size);
else
memcpy(dmabuf, sgbuf, sg[i].length);
kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
dmabuf += 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)
* we do not transfer too much.
*/
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)
memcpy(sgbuf, dmabuf, size);
else
@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
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
@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
if (data->bytes_xfered == host->size) {
wbsd_kunmap_sg(host);
if (data->bytes_xfered == host->size)
return;
}
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
wbsd_kunmap_sg(host);
/*
* Get next entry. Check if last.
*/
@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
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
* hardware problem. The chip doesn't trigger
@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
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
@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
if (data->bytes_xfered == host->size) {
wbsd_kunmap_sg(host);
if (data->bytes_xfered == host->size)
return;
}
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
wbsd_kunmap_sg(host);
/*
* Get next entry. Check if last.
*/
@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
return;
}
buffer = wbsd_kmap_sg(host);
buffer = wbsd_sg_to_buffer(host);
}
}
}
wbsd_kunmap_sg(host);
/*
* The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we
@ -909,6 +889,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
* transfered.
*/
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.
*/
@ -1343,16 +1362,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->max_phys_segs = 128;
/*
* Maximum number of sectors in one transfer. Also limited by 64kB
* buffer.
* Maximum request size. Also limited by 64KiB buffer.
*/
mmc->max_sectors = 128;
mmc->max_req_size = 65536;
/*
* Maximum segment size. Could be one segment with the maximum number
* of segments.
* of bytes.
*/
mmc->max_seg_size = mmc->max_sectors * 512;
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_blk_count = mmc->max_req_size;
dev_set_drvdata(dev, mmc);

Просмотреть файл

@ -154,7 +154,6 @@ struct wbsd_host
struct scatterlist* cur_sg; /* Current SG entry */
unsigned int num_sg; /* Number of entries left */
void* mapped_sg; /* vaddr of mapped sg */
unsigned int offset; /* Offset into current entry */
unsigned int remain; /* Data left in curren entry */

Просмотреть файл

@ -71,6 +71,7 @@ struct mmc_card {
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
#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_BLOCKADDR (1<<6) /* card uses block-addressing */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
@ -87,6 +88,7 @@ struct mmc_card {
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#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_dead(c) ((c)->state |= MMC_STATE_DEAD)
@ -94,6 +96,7 @@ struct mmc_card {
#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_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_id(c) ((c)->dev.bus_id)

Просмотреть файл

@ -92,8 +92,10 @@ struct mmc_host {
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_phys_segs; /* see blk_queue_max_phys_segments */
unsigned short max_sectors; /* see blk_queue_max_sectors */
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 */
struct mmc_ios ios; /* current io bus settings */
@ -106,8 +108,9 @@ struct mmc_host {
struct list_head cards; /* devices attached to this host */
wait_queue_head_t wq;
spinlock_t lock; /* card_busy lock */
struct mmc_card *card_busy; /* the MMC card claiming host */
spinlock_t lock; /* claimed lock */
unsigned int claimed:1; /* host exclusively claimed */
struct mmc_card *card_selected; /* the selected MMC card */
struct delayed_work detect;
@ -126,6 +129,7 @@ static inline void *mmc_priv(struct mmc_host *host)
}
#define mmc_dev(x) ((x)->parent)
#define mmc_classdev(x) (&(x)->class_dev)
#define mmc_hostname(x) ((x)->class_dev.bus_id)
extern int mmc_suspend_host(struct mmc_host *, pm_message_t);

Просмотреть файл

@ -43,6 +43,7 @@ struct mmc_command {
#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
#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))

Просмотреть файл

@ -79,9 +79,12 @@
#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* SD commands type argument response */
/* class 8 */
/* class 0 */
/* This is basically the same command as for MMC with some quirks. */
#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 */
/* Application commands */
@ -114,6 +117,14 @@
* [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
Type

Просмотреть файл

@ -735,9 +735,11 @@
#define PCI_DEVICE_ID_TI_TVP4020 0x3d07
#define PCI_DEVICE_ID_TI_4450 0x8011
#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_X515 0x8036
#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_1031 0xac13
#define PCI_DEVICE_ID_TI_1131 0xac15
@ -765,6 +767,7 @@
#define PCI_DEVICE_ID_TI_1510 0xac56
#define PCI_DEVICE_ID_TI_X620 0xac8d
#define PCI_DEVICE_ID_TI_X420 0xac8e
#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f
#define PCI_VENDOR_ID_SONY 0x104d
@ -1971,6 +1974,7 @@
#define PCI_DEVICE_ID_TOPIC_TP560 0x0000
#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_1225 0x1225
#define PCI_DEVICE_ID_ENE_1410 0x1410

Просмотреть файл

@ -17,7 +17,7 @@
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/scatterlist.h>
#include <linux/kthread.h>
/* Host registers (relative to pci base address): */
enum {
@ -62,11 +62,10 @@ enum {
#define TIFM_IRQ_ENABLE 0x80000000
#define TIFM_IRQ_SOCKMASK 0x00000001
#define TIFM_IRQ_CARDMASK 0x00000100
#define TIFM_IRQ_FIFOMASK 0x00010000
#define TIFM_IRQ_SOCKMASK(x) (x)
#define TIFM_IRQ_CARDMASK(x) ((x) << 8)
#define TIFM_IRQ_FIFOMASK(x) ((x) << 16)
#define TIFM_IRQ_SETALL 0xffffffff
#define TIFM_IRQ_SETALLSOCK 0x0000000f
#define TIFM_CTRL_LED 0x00000040
#define TIFM_CTRL_FAST_CLK 0x00000100
@ -89,10 +88,9 @@ struct tifm_dev {
char __iomem *addr;
spinlock_t lock;
tifm_media_id media_id;
char wq_name[KOBJ_NAME_LEN];
struct workqueue_struct *wq;
unsigned int socket_id;
unsigned int (*signal_irq)(struct tifm_dev *sock,
void (*signal_irq)(struct tifm_dev *sock,
unsigned int sock_irq_status);
struct tifm_driver *drv;
@ -103,24 +101,23 @@ struct tifm_driver {
tifm_media_id *id_table;
int (*probe)(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 tifm_adapter {
char __iomem *addr;
unsigned int irq_status;
unsigned int insert_mask;
unsigned int remove_mask;
spinlock_t lock;
unsigned int irq_status;
unsigned int socket_change_set;
wait_queue_head_t change_set_notify;
unsigned int id;
unsigned int max_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;
unsigned int num_sockets;
struct tifm_dev **sockets;
struct task_struct *media_switcher;
struct class_device cdev;
struct device *dev;
@ -130,9 +127,9 @@ struct tifm_adapter {
struct tifm_adapter *tifm_alloc_adapter(void);
void tifm_free_device(struct device *dev);
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);
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);
void tifm_unregister_driver(struct tifm_driver *drv);
void tifm_eject(struct tifm_dev *sock);