commit: http://blackfin.uclinux.org/git/?p=linux-kernel;a=commitdiff;h=f09bb272eb50dc3e011e87ad03756c43f55d2b77
branch: http://blackfin.uclinux.org/git/?p=linux-kernel;a=shortlog;h=refs/heads/trunk

Signed-off-by: Steven Miao <[email protected]>
Signed-off-by: Bob Liu <[email protected]>
---
 drivers/char/bfin_lp.c |  147 +++++++++++++++++++++++-------------------------
 1 files changed, 71 insertions(+), 76 deletions(-)

diff --git a/drivers/char/bfin_lp.c b/drivers/char/bfin_lp.c
index a07a354..e89f9b3 100644
--- a/drivers/char/bfin_lp.c
+++ b/drivers/char/bfin_lp.c
@@ -24,6 +24,8 @@
 #include <linux/kfifo.h>
 #include <linux/completion.h>
 
+#include <linux/workqueue.h>
+
 #include <asm/irq.h>
 #include <asm/blackfin.h>
 #include <asm/dma.h>
@@ -33,9 +35,7 @@
 #include <asm/gptimers.h>
 
 /* fifo size in elements (ints) */
-#define FIFO_SIZE       32
-
-
+#define FIFO_SIZE      1024
 
 #define LINKPORT_DRVNAME "bfin-linkport"
 
@@ -47,6 +47,7 @@
 #define LP_CTL_RRQMSK  0x200
 #define LP_CTL_ITMSK  0x800
 
+#define LP_STAT_DONE 0x1000
 #define LP_STAT_LTRQ 0x1
 #define LP_STAT_LRRQ 0x2
 #define LP_STAT_LPIT 0x8
@@ -134,6 +135,8 @@ struct bfin_lp_dev {
 	volatile struct bfin_lp_register *regs;
 	wait_queue_head_t rx_waitq;
 	spinlock_t lock;
+	struct workqueue_struct *workqueue;
+	struct work_struct transfer_work;
 	int linkport_num;
 	int dma_chan;
 	int status;
@@ -190,37 +193,6 @@ int bfin_lp_config_channel(struct bfin_lp_dev *lpdev, int direction)
 	lpdev->regs->ctl = reg;
 
 	SSYNC();
-	reg = lpdev->regs->ctl;
-	SSYNC();
-	return 0;
-}
-
-int bfin_lp_tx_word(struct bfin_lp_dev *lpdev, uint32_t *buf, int count)
-{
-	uint32_t reg;
-
-	reg = lpdev->regs->ctl;
-	SSYNC();
-
-	printk("2 ctl %08x = %08x\n", &lpdev->regs->ctl, reg);
-
-	printk("queue len: %u\n", kfifo_len(&lpdev->lpfifo));
-
-	return 0;
-}
-
-int bfin_lp_rx_word(struct bfin_lp_dev *lpdev, uint32_t *buf, int count)
-{
-	uint32_t *word = buf;
-	while (count) {
-
-		count--;
-		word++;
-
-		while (lpdev->regs->stat & LP_STAT_LPBS);
-
-	}
-
 	return 0;
 }
 
@@ -270,31 +242,60 @@ int bfin_lp_get_rx_fifo(struct bfin_lp_dev *lpdev)
 		return 0;
 }
 
+static void lp_rx_fifo(struct bfin_lp_dev *dev)
+{
+	int cnt;
+
+	cnt = bfin_lp_get_rx_fifo(dev);
+	while (cnt) {
+		unsigned int data;
+		data = "">
+		if (!kfifo_put(&dev->lpfifo, &data))
+			goto out;
+		cnt--;
+	}
+out:
+	enable_irq(dev->irq);
+	/* wake up read/write block. */
+	wake_up_interruptible(&dev->rx_waitq);
+}
+
+static void transfer_fn(struct work_struct *work)
+{
+	struct bfin_lp_dev *dev = container_of(work,
+			struct bfin_lp_dev, transfer_work);
+
+	if (dev->status == LP_STAT_LTRQ) {
+		unsigned int data = "">
+		while (kfifo_get(&dev->lpfifo, &data)) {
+			if ((dev->regs->stat & LP_STAT_FFST) == 0x60)
+				break;
+			while (dev->regs->stat & LP_STAT_LPBS);
+			dev->regs->tx = data;
+		}
+		if (kfifo_len(&dev->lpfifo) == 0) {
+			dev->status = LP_STAT_DONE;
+			if (dev->regs->stat & LP_STAT_LPBS) {
+				enable_irq(dev->irq);
+				return;
+			}
+			complete(&dev->complete);
+		}
+	} else if (dev->status == LP_STAT_DONE) {
+		kfifo_reset(&dev->lpfifo);
+	} else {
+		lp_rx_fifo(dev);
+	}
+}
+
 static irqreturn_t bfin_lp_irq(int irq, void *dev_id)
 {
 	struct bfin_lp_dev *dev = (struct bfin_lp_dev *)dev_id;
-	int cnt;
 	unsigned long flags;
 	uint32_t stat = dev->regs->stat;
 
 	pr_debug("bfin lp irq %d stat %x dev %p status %d\n", irq, stat, dev, dev->status);
 
-	cnt = bfin_lp_get_rx_fifo(dev);
-	if (cnt) {
-		spin_lock_irqsave(&dev->lock, flags);
-		while (cnt) {
-			unsigned int data;
-			data = "">
-			if (!kfifo_put(&dev->lpfifo, &data))
-				goto out;
-			cnt--;
-		}
-
-		spin_unlock_irqrestore(&dev->lock, flags);
-		dev->regs->ctl = 0;
-		/* wake up read/write block. */
-		wake_up_interruptible(&dev->rx_waitq);
-	}
 	if (stat & LP_STAT_LTRQ) {
 		if (kfifo_len(&dev->lpfifo)) {
 			dev->status = LP_STAT_LTRQ;
@@ -309,21 +310,8 @@ static irqreturn_t bfin_lp_irq(int irq, void *dev_id)
 		goto out;
 	}
 
-	if (dev->status == LP_STAT_LTRQ) {
-		unsigned int data = "">
-		if (kfifo_get(&dev->lpfifo, &data)) {
-			dev->regs->tx = data;
-		}
-		if (kfifo_len(&dev->lpfifo) == 0) {
-			dev->status = 0;
-			dev->regs->ctl = 0;
-			complete(&dev->complete);
-		}
-	} else if (dev->status == LP_STAT_LRRQ) {
-		unsigned int data;
-		data = "">
-	}
-
+	disable_irq_nosync(irq);
+	queue_work(dev->workqueue, &dev->transfer_work);
 out:
 	dev->regs->stat = stat;
 	dev->count++;
@@ -354,6 +342,7 @@ static int bfin_lp_open(struct inode *inode, struct file *filp)
 
 	if (peripheral_request_list(dev->per_linkport, LINKPORT_DRVNAME)) {
 		printk("Requesting Peripherals failed\n");
+
 		return ret;
 	}
 
@@ -372,6 +361,12 @@ static int bfin_lp_open(struct inode *inode, struct file *filp)
 		goto free_dma;
 	}
 
+	dev->workqueue = create_singlethread_workqueue("linkport_work");
+	if (!dev->workqueue) {
+		printk(KERN_ERR "create workqueue failed\n");
+		goto free_dma;
+	}
+
 	dev->regs->div = 1;
 	dev->regs->stat = 0xFF;
 	dev->regs->ctl = 0;
@@ -389,6 +384,13 @@ free_per:
 static int bfin_lp_release(struct inode *inode, struct file *filp)
 {
 	struct bfin_lp_dev *dev = filp->private_data;
+
+	wait_for_completion(&dev->complete);
+
+	dev->regs->ctl = 0;
+
+	enable_irq(dev->irq);
+	destroy_workqueue(dev->workqueue);
 	kfifo_free(&dev->lpfifo);
 	peripheral_free_list(dev->per_linkport);
 	free_dma(dev->dma_chan);
@@ -414,7 +416,6 @@ static ssize_t bfin_lp_read(struct file *filp, char *buf, size_t count, loff_t *
 
 	dev->regs->ctl |= LP_CTL_EN;
 
-
 	while (n) {
 		fifo_cnt = kfifo_len(&dev->lpfifo);
 		if (!fifo_cnt) {
@@ -422,7 +423,7 @@ static ssize_t bfin_lp_read(struct file *filp, char *buf, size_t count, loff_t *
 			continue;
 		}
 
-		ret = kfifo_to_user(&dev->lpfifo, buf, fifo_cnt, &copied);
+		ret = kfifo_to_user(&dev->lpfifo, buf, fifo_cnt * 4, &copied);
 		n -= fifo_cnt;
 	}
 
@@ -438,17 +439,10 @@ static ssize_t bfin_lp_write(struct file *filp, const char *buf, size_t count, l
 
 	ret = kfifo_from_user(&dev->lpfifo, buf, count, &copied);
 
-	if (kfifo_peek(&dev->lpfifo, &i))
-		printk(KERN_INFO "%x\n", i);
-
 	dev->regs->div = 1;
 
 	bfin_lp_config_channel(dev, 1);
 
-	wait_for_completion(&dev->complete);
-
-	dev->regs->ctl = 0;
-
 	return ret ? ret : copied;
 }
 
@@ -628,7 +622,7 @@ static int __init bfin_linkport_init(void)
 	INIT_LIST_HEAD(&linkport_dev->lp_dev);
 	spin_lock_init(&linkport_dev->lp_dev_lock);
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < 4; i++) {
 		struct device *dev;
 		dev = device_create(linkport_dev->class, NULL, lp_dev + i, &lp_dev_info[i], "linkport%d", i);
 		if (!dev)
@@ -637,6 +631,7 @@ static int __init bfin_linkport_init(void)
 		lp_dev_info[i].linkport_num = i;
 		spin_lock_init(&lp_dev_info[i].lock);
 		init_waitqueue_head(&lp_dev_info[i].rx_waitq);
+		INIT_WORK(&lp_dev_info[i].transfer_work, transfer_fn);
 		INIT_LIST_HEAD(&lp_dev_info[i].list);
 		init_completion(&lp_dev_info[i].complete);
 		list_add(&lp_dev_info[i].list, &linkport_dev->lp_dev);
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to