Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2442d310 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* '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
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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


+213 −189
Original line number Original line Diff line number Diff line
@@ -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);
	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_lock_irqsave(&fm->lock, flags);
		}
	fm->socket_change_set |= 1 << sock->socket_id;
	}
	wake_up_all(&fm->change_set_notify);
	spin_unlock_irqrestore(&fm->lock, flags);
	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)
	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)
					     | TIFM_IRQ_CARDMASK(1));


			if (fm->sockets[cnt]) {
			if (sock && sock_irq_status)
				if (sock_irq_status &&
				sock->signal_irq(sock, 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;
			}
		}
		}

		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
	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
	}
	}


	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,42 +119,67 @@ 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;

	while (1) {
		rc = wait_event_interruptible(fm->change_set_notify,
					      fm->socket_change_set);
		if (rc == -ERESTARTSYS)
			try_to_freeze();


	if (!class_device_get(&fm->cdev))
		return;
		spin_lock_irqsave(&fm->lock, flags);
		spin_lock_irqsave(&fm->lock, flags);
	insert_mask = fm->insert_mask;
		socket_change_set = fm->socket_change_set;
	fm->insert_mask = 0;
		fm->socket_change_set = 0;
	if (fm->inhibit_new_cards) {

		spin_unlock_irqrestore(&fm->lock, flags);
		dev_dbg(fm->dev, "checking media set %x\n",
		class_device_put(&fm->cdev);
			socket_change_set);
		return;

	}
		if (kthread_should_stop())
			socket_change_set = (1 << fm->num_sockets) - 1;
		spin_unlock_irqrestore(&fm->lock, flags);
		spin_unlock_irqrestore(&fm->lock, flags);


	for (cnt = 0; cnt < fm->max_sockets; cnt++) {
		if (!socket_change_set)
		if (!(insert_mask & (1 << cnt)))
			continue;

		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
				       ": demand removing card from socket %d\n",
				       cnt);
				fm->sockets[cnt] = NULL;
				spin_unlock_irqrestore(&fm->lock, flags);
				device_unregister(&sock->dev);
				spin_lock_irqsave(&fm->lock, flags);
				writel(0x0e00,
				       tifm_7xx1_sock_addr(fm->addr, cnt)
				       + SOCK_CONTROL);
			}
			if (kthread_should_stop())
				continue;
				continue;


		media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
			spin_unlock_irqrestore(&fm->lock, flags);
						       fm->max_sockets == 2);
			media_id = tifm_7xx1_toggle_sock_power(
					tifm_7xx1_sock_addr(fm->addr, cnt),
					fm->num_sockets == 2);
			if (media_id) {
			if (media_id) {
			ok_to_register = 0;
				sock = tifm_alloc_device(fm);
			new_sock = tifm_alloc_device(fm, cnt);
				if (sock) {
			if (new_sock) {
					sock->addr = tifm_7xx1_sock_addr(fm->addr,
				new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
									 cnt);
									 cnt);
				new_sock->media_id = media_id;
					sock->media_id = media_id;
					sock->socket_id = cnt;
					switch (media_id) {
					switch (media_id) {
					case 1:
					case 1:
						card_name = "xd";
						card_name = "xd";
@@ -217,81 +191,135 @@ static void tifm_7xx1_insert_media(struct work_struct *work)
						card_name = "sd";
						card_name = "sd";
						break;
						break;
					default:
					default:
					break;
						tifm_free_device(&sock->dev);
						spin_lock_irqsave(&fm->lock, flags);
						continue;
					}
					}
				snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
					snprintf(sock->dev.bus_id, BUS_ID_SIZE,
					"tifm_%s%u:%u", card_name, fm->id, cnt);
						 "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",
					       ": %s card detected in socket %d\n",
					       card_name, cnt);
					       card_name, cnt);
					if (!device_register(&sock->dev)) {
						spin_lock_irqsave(&fm->lock, flags);
						spin_lock_irqsave(&fm->lock, flags);
						if (!fm->sockets[cnt]) {
						if (!fm->sockets[cnt]) {
					fm->sockets[cnt] = new_sock;
							fm->sockets[cnt] = sock;
					ok_to_register = 1;
							sock = NULL;
						}
						}
						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);
					}
					}
					if (sock)
						tifm_free_device(&sock->dev);
				}
				spin_lock_irqsave(&fm->lock, flags);
			}
			}
		}
		}
		writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,

		if (!kthread_should_stop()) {
			writel(TIFM_IRQ_FIFOMASK(socket_change_set)
			       | TIFM_IRQ_CARDMASK(socket_change_set),
			       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
			       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
		writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
			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);
			       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) {
	writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
				spin_unlock_irqrestore(&fm->lock, flags);
	class_device_put(&fm->cdev);
				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)
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);
	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;
	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_restore_state(dev);
        pci_enable_device(dev);
	pci_set_power_state(dev, PCI_D0);
	pci_set_power_state(dev, PCI_D0);
	pci_restore_state(dev);
	rc = pci_enable_device(dev);
	if (rc)
		return rc;
	pci_set_master(dev);
	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->socket_change_set |= 1 << cnt;

			fm->sockets[cnt]->media_id = new_ids[cnt];
		}
	}

	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
	if (!fm->socket_change_set) {
		spin_unlock_irqrestore(&fm->lock, flags);
		return 0;
	} else {
		fm->socket_change_set = 0;
		spin_unlock_irqrestore(&fm->lock, flags);
	}

	wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);

	spin_lock_irqsave(&fm->lock, flags);
	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
	       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
	       fm->addr + FM_SET_INTERRUPT_ENABLE);
	fm->insert_mask = 0xf;
	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)
{
{
@@ -324,14 +352,13 @@ 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;
	fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
			      GFP_KERNEL);
			      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);


@@ -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)
	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)
}
}


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 },
	{ }
	{ }
};
};


+49 −16
Original line number Original line Diff line number Diff line
@@ -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,
	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)
	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)
}
}
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)
	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);
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)
	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)
	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);
}
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -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;
+12 −1
Original line number Original line Diff line number Diff line
@@ -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,
	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,
	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)
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)
		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);
Loading