commit: http://blackfin.uclinux.org/git/?p=linux-kernel;a=commitdiff;h=a3795b8f76ccf5afd4dbef796f93d563194ccb58
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 |  189 ++++++++++++++++++++++++++++++------------------
 1 files changed, 118 insertions(+), 71 deletions(-)

diff --git a/drivers/char/bfin_lp.c b/drivers/char/bfin_lp.c
index e7c2103..a07a354 100644
--- a/drivers/char/bfin_lp.c
+++ b/drivers/char/bfin_lp.c
@@ -22,6 +22,7 @@
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/kfifo.h>
+#include <linux/completion.h>
 
 #include <asm/irq.h>
 #include <asm/blackfin.h>
@@ -31,15 +32,20 @@
 
 #include <asm/gptimers.h>
 
+/* fifo size in elements (ints) */
+#define FIFO_SIZE       32
+
+
+
 #define LINKPORT_DRVNAME "bfin-linkport"
 
 #define BFIN_LP_DMA_MODE
 
 #define LP_CTL_EN 0x1
 #define LP_CTL_TRAN 0x8
-#define LP_CTL_TRQMSK  0x10
-#define LP_CTL_RRQMSK  0x20
-#define LP_CTL_ITMSK  0x80
+#define LP_CTL_TRQMSK  0x100
+#define LP_CTL_RRQMSK  0x200
+#define LP_CTL_ITMSK  0x800
 
 #define LP_STAT_LTRQ 0x1
 #define LP_STAT_LRRQ 0x2
@@ -125,15 +131,17 @@ struct bfin_linkport {
 struct bfin_lp_dev {
 	struct list_head list;
 	struct device *device;
-	volatile struct bfin_lp_register __iomem *regs;
+	volatile struct bfin_lp_register *regs;
 	wait_queue_head_t rx_waitq;
-	int rx_fifo_cnt;
-	int tx_fifo_cnt;
 	spinlock_t lock;
 	int linkport_num;
 	int dma_chan;
+	int status;
 	int irq;
 	int status_irq;
+	int count;
+	DECLARE_KFIFO_PTR(lpfifo, unsigned int);
+	struct completion complete;
 	const unsigned short *per_linkport;
 };
 
@@ -143,24 +151,28 @@ struct bfin_lp_dev lp_dev_info[4] = {
 	{
 		.regs = LP0_CTL,
 		.irq = IRQ_LP0,
+		.status_irq = IRQ_LP0_STAT,
 		.per_linkport = per_req_lp0,
 		.dma_chan = CH_LP0,
 	},
 	{
 		.regs = LP1_CTL,
 		.irq = IRQ_LP1,
+		.status_irq = IRQ_LP1_STAT,
 		.per_linkport = per_req_lp1,
 		.dma_chan = CH_LP1,
 	},
 	{
 		.regs = LP2_CTL,
 		.irq = IRQ_LP2,
+		.status_irq = IRQ_LP2_STAT,
 		.per_linkport = per_req_lp2,
 		.dma_chan = CH_LP2,
 	},
 	{
 		.regs = LP3_CTL,
 		.irq = IRQ_LP3,
+		.status_irq = IRQ_LP3_STAT,
 		.per_linkport = per_req_lp3,
 		.dma_chan = CH_LP3,
 	},
@@ -171,32 +183,28 @@ int bfin_lp_config_channel(struct bfin_lp_dev *lpdev, int direction)
 {
 	uint32_t reg;
 	if (direction)
-		reg = LP_CTL_TRAN | LP_CTL_RRQMSK | LP_CTL_RRQMSK | LP_CTL_ITMSK;
+		reg = LP_CTL_TRAN | LP_CTL_TRQMSK;
 	else
-		reg = LP_CTL_RRQMSK | LP_CTL_RRQMSK | LP_CTL_ITMSK;
+		reg =  LP_CTL_RRQMSK;
 
 	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 *word = buf;
-
-	lpdev->regs->div = 1;
-	lpdev->regs->ctl |= LP_CTL_EN;
+	uint32_t reg;
 
-	while (count) {
-		if ((lpdev->regs->stat & LP_STAT_FFST) == 6)
-			return -EAGAIN;
+	reg = lpdev->regs->ctl;
+	SSYNC();
 
-		while (lpdev->regs->stat & LP_STAT_LPBS);
+	printk("2 ctl %08x = %08x\n", &lpdev->regs->ctl, reg);
 
-		lpdev->regs->tx = *word;
-		count--;
-		word++;
-	}
+	printk("queue len: %u\n", kfifo_len(&lpdev->lpfifo));
 
 	return 0;
 }
@@ -206,11 +214,6 @@ int bfin_lp_rx_word(struct bfin_lp_dev *lpdev, uint32_t *buf, int count)
 	uint32_t *word = buf;
 	while (count) {
 
-		if (!(lpdev->regs->stat & LP_STAT_LRRQ))
-			return -EAGAIN;
-
-		*word = lpdev->regs->rx;
-
 		count--;
 		word++;
 
@@ -270,27 +273,60 @@ int bfin_lp_get_rx_fifo(struct bfin_lp_dev *lpdev)
 static irqreturn_t bfin_lp_irq(int irq, void *dev_id)
 {
 	struct bfin_lp_dev *dev = (struct bfin_lp_dev *)dev_id;
-	uint32_t word;
 	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);
-		dev->tx_fifo_cnt = cnt;
+		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;
+			dev->regs->ctl |= LP_CTL_EN;
+		}
+		goto out;
+	}
 
-	/* wake up read/write block. */
-	printk("bfin lp irq stat %x cnt %d\n", dev->regs->stat, cnt);
-
-	if (dev->regs->stat & LP_STAT_LTRQ) {
-		printk("send word\n");
-		dev->regs->tx = 0xffaa55bb;
+	if (stat & LP_STAT_LRRQ) {
+		dev->status = LP_STAT_LRRQ;
+		dev->regs->ctl |= LP_CTL_EN;
+		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 = "">
+	}
 
+out:
+	dev->regs->stat = stat;
+	dev->count++;
 	return IRQ_HANDLED;
 }
 
@@ -310,6 +346,12 @@ static int bfin_lp_open(struct inode *inode, struct file *filp)
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
+	ret = kfifo_alloc(&dev->lpfifo, FIFO_SIZE, GFP_KERNEL);
+	if (ret) {
+		printk(KERN_ERR "error kfifo_alloc\n");
+		return ret;
+	}
+
 	if (peripheral_request_list(dev->per_linkport, LINKPORT_DRVNAME)) {
 		printk("Requesting Peripherals failed\n");
 		return ret;
@@ -321,12 +363,18 @@ static int bfin_lp_open(struct inode *inode, struct file *filp)
 	}
 
 	if (request_irq(dev->irq, bfin_lp_irq, 0, LINKPORT_DRVNAME, dev)) {
-		printk("Requesting irq failed\n");
+		printk(KERN_ERR "Requesting irq failed\n");
 		goto free_dma;
 	}
 
+	if (request_irq(dev->status_irq, bfin_lp_irq, 0, LINKPORT_DRVNAME, dev)) {
+		printk(KERN_ERR "Requesting status irq failed\n");
+		goto free_dma;
+	}
 
 	dev->regs->div = 1;
+	dev->regs->stat = 0xFF;
+	dev->regs->ctl = 0;
 	SSYNC();
 
 	return 0;
@@ -341,9 +389,11 @@ free_per:
 static int bfin_lp_release(struct inode *inode, struct file *filp)
 {
 	struct bfin_lp_dev *dev = filp->private_data;
+	kfifo_free(&dev->lpfifo);
 	peripheral_free_list(dev->per_linkport);
 	free_dma(dev->dma_chan);
 	free_irq(dev->irq, dev);
+	free_irq(dev->status_irq, dev);
 	return 0;
 }
 
@@ -351,54 +401,55 @@ static ssize_t bfin_lp_read(struct file *filp, char *buf, size_t count, loff_t *
 {
 	struct bfin_lp_dev *dev = filp->private_data;
 	int fifo_cnt = 0;
-	int rx_byte = 0;
-	uint32_t word[4];
+	unsigned int copied;
+	unsigned int n;
+	int ret;
+
+	n = count / 4;
+	count = 4 * n;
 
-	printk("%s count %d\n", __func__, count);
+	dev->regs->div = 1;
 
 	bfin_lp_config_channel(dev, 0);
 
 	dev->regs->ctl |= LP_CTL_EN;
 
 
-	while (count) {
-		fifo_cnt = bfin_lp_get_rx_fifo(dev);
+	while (n) {
+		fifo_cnt = kfifo_len(&dev->lpfifo);
 		if (!fifo_cnt) {
-			wait_event_interruptible(dev->rx_waitq, dev->rx_fifo_cnt);
+			wait_event_interruptible(dev->rx_waitq, kfifo_len(&dev->lpfifo) != 0);
 			continue;
 		}
 
-		bfin_lp_rx_word(dev, word, 1);
-		count--;
-		rx_byte += 4;
-
-		if (put_user(word[0], (uint32_t *)(buf + rx_byte)))
-			return -EFAULT;
-
+		ret = kfifo_to_user(&dev->lpfifo, buf, fifo_cnt, &copied);
+		n -= fifo_cnt;
 	}
 
 	return count;
 }
 
-static ssize_t bfin_lp_write(struct file *filp, char *buf, size_t count, loff_t *pos)
+static ssize_t bfin_lp_write(struct file *filp, const char *buf, size_t count, loff_t *pos)
 {
 	struct bfin_lp_dev *dev = filp->private_data;
-	unsigned long trans = count / 4 + 1;
-	uint32_t word;
+	unsigned int copied;
 	int ret;
+	int i;
+
+	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;
 
-	ret = kstrtou32_from_user(buf, 1, 16, &word);
-	printk("%s count %d\n", __func__, count);
 	bfin_lp_config_channel(dev, 1);
 
-	while (trans) {
-		ret = bfin_lp_tx_word(dev, &word, 1);
-		if (ret)
-			return 0;
-		trans--;
-	}
+	wait_for_completion(&dev->complete);
 
-	return count;
+	dev->regs->ctl = 0;
+
+	return ret ? ret : copied;
 }
 
 static long bfin_lp_ioctl(struct file *filp, uint cmd, unsigned long arg)
@@ -422,7 +473,6 @@ linkport_status_show(struct class *class, struct class_attribute *attr, char *bu
 	char *p = buf;
 	struct bfin_lp_dev *dev;
 
-	printk("%s\n", __func__);
 	p += sprintf(p, "linkport status\n");
 	list_for_each_entry(dev, &linkport_dev->lp_dev, list) {
 		p += sprintf(p, "linkport num %d\n", dev->linkport_num);
@@ -436,7 +486,6 @@ linkport_reg_show(struct class *class, struct class_attribute *attr, char *buf)
 	char *p = buf;
 	struct bfin_lp_dev *dev;
 
-	printk("%s\n", __func__);
 	p += sprintf(p, "linkport status\n");
 	list_for_each_entry(dev, &linkport_dev->lp_dev, list) {
 		p += sprintf(p, "linkport num %d\n", dev->linkport_num);
@@ -447,10 +496,9 @@ linkport_reg_show(struct class *class, struct class_attribute *attr, char *buf)
 }
 
 static ssize_t
-linkport_reg_store(struct class *class, struct class_attribute *attr, char *buf, size_t count)
+linkport_reg_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
 {
-	char *p = buf;
-	struct bfin_lp_dev *dev;
+	char *p;
 	int rw = 0;
 	char buffer[64];
 	uint32_t res;
@@ -473,10 +521,10 @@ linkport_reg_store(struct class *class, struct class_attribute *attr, char *buf,
 	else if (p[0] == 'w')
 		rw = 1;
 	else
-		printk("-EINVAL\n");
+		printk(KERN_DEBUG "-EINVAL\n");
 
 	if (p[1] < '0' && p[1] > '9')
-		printk("-EINVAL2\n");
+		printk(KERN_DEBUG "-EINVAL2\n");
 
 	res = simple_strtoul(&p[1], &endp, 10);
 
@@ -487,7 +535,7 @@ linkport_reg_store(struct class *class, struct class_attribute *attr, char *buf,
 	else if (res == 32)
 		p += 3;
 	else
-		printk("-EINVAL3\n");
+		printk(KERN_DEBUG "-EINVAL3\n");
 
 
 	while (*p == ' ')
@@ -515,7 +563,7 @@ linkport_reg_store(struct class *class, struct class_attribute *attr, char *buf,
 			value = bfin_read32(addr);
 			break;
 		}
-		printk("write addr %08x reg %08x\n", addr, value);
+		printk(KERN_DEBUG "write addr %08x reg %08x\n", addr, value);
 	} else {
 		switch (res) {
 		case 8:
@@ -528,7 +576,7 @@ linkport_reg_store(struct class *class, struct class_attribute *attr, char *buf,
 			value = bfin_read32(addr);
 			break;
 		}
-		printk("read addr %08x reg %08x\n", addr, value);
+		printk(KERN_DEBUG "read addr %08x reg %08x\n", addr, value);
 	}
 	return count;
 }
@@ -549,8 +597,6 @@ static int __init bfin_linkport_init(void)
 	dev_t lp_dev;
 	int i;
 
-	printk("%s\n", __func__);
-
 	linkport_dev = kzalloc(sizeof(*linkport_dev), GFP_KERNEL);
 	if (!linkport_dev) {
 		return -ENOMEM;
@@ -592,6 +638,7 @@ static int __init bfin_linkport_init(void)
 		spin_lock_init(&lp_dev_info[i].lock);
 		init_waitqueue_head(&lp_dev_info[i].rx_waitq);
 		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