Title: [9163] trunk: [#5344] bfin_sport: add support for ADC/DAC.
Revision
9163
Author
lliubbo
Date
2010-09-25 03:05:27 -0400 (Sat, 25 Sep 2010)

Log Message

[#5344] bfin_sport: add support for ADC/DAC.

In order to support ADC/DAC demo, add a mode NDSO_MODE
in bfin_sport.c for userspace app ndso/awg to use.

Modified Paths

Diff

Modified: trunk/arch/blackfin/include/asm/bfin_sport.h (9162 => 9163)


--- trunk/arch/blackfin/include/asm/bfin_sport.h	2010-09-25 05:38:34 UTC (rev 9162)
+++ trunk/arch/blackfin/include/asm/bfin_sport.h	2010-09-25 07:05:27 UTC (rev 9163)
@@ -13,6 +13,7 @@
 #define NORM_MODE	0x0
 #define TDM_MODE	0x1
 #define I2S_MODE	0x2
+#define NDSO_MODE	0x3
 
 /* Data format, normal, a-law or u-law */
 #define NORM_FORMAT	0x0
@@ -56,6 +57,8 @@
 /* Userspace interface */
 #define SPORT_IOC_MAGIC		'P'
 #define SPORT_IOC_CONFIG	_IOWR('P', 0x01, struct sport_config)
+#define SPORT_IOC_GET_SYSTEMCLOCK         _IOR('P', 0x02, unsigned long)
+#define SPORT_IOC_SET_BAUDRATE            _IOW('P', 0x03, unsigned long)
 
 #ifdef __KERNEL__
 

Modified: trunk/drivers/char/bfin_sport.c (9162 => 9163)


--- trunk/drivers/char/bfin_sport.c	2010-09-25 05:38:34 UTC (rev 9162)
+++ trunk/drivers/char/bfin_sport.c	2010-09-25 07:05:27 UTC (rev 9163)
@@ -31,6 +31,10 @@
 #include <asm/cacheflush.h>
 #include <asm/portmux.h>
 
+static int sport_mode;
+static int sport_clkdiv;
+static int irq_notfreed;
+
 struct sport_dev {
 	int dma_rx_chan;
 	int dma_tx_chan;
@@ -128,6 +132,22 @@
 	return 0;
 }
 
+static u16 hz_to_sport_clkdiv(u32 speed_hz)
+{
+	u_long clk, sclk = get_sclk();
+	int div = (sclk / (2 * speed_hz)) - 1;
+
+	if (div < 0)
+		div = 0;
+
+	clk = sclk / (2 * (div + 1));
+
+	if (clk > speed_hz)
+		div++;
+
+	return div;
+}
+
 static int sport_configure(struct sport_dev *dev, struct sport_config *config)
 {
 	unsigned int tcr1, tcr2, rcr1, rcr2;
@@ -175,6 +195,12 @@
 
 		rcr1 |= (RCKFE | RFSR);
 		rcr2 |= RSFSE;
+	} else if (config->mode == NDSO_MODE) {
+		sport_mode = NDSO_MODE;
+		rcr1 = RFSR | LARFS | LRFS;
+		tcr1 = ITCLK | ITFS | TFSR | LATFS | LTFS;
+		clkdiv = sport_clkdiv;
+		fsdiv = config->word_len - 1;
 	} else {
 		tcr1 |= (config->lsb_first << 4) | (config->fsync << 10) |
 		      (config->data_indep << 11) | (config->act_low << 12) |
@@ -282,12 +308,10 @@
 	/* Wait for the last byte sent out */
 	udelay(500);
 	pr_debug("%s status:%x\n", __func__, status);
-
 	dev->regs->tcr1 &= ~TSPEN;
 	SSYNC();
 	enable_irq(dev->err_irq);
 	disable_dma(dev->dma_tx_chan);
-
 	complete(&dev->c);
 
 	/* Clear the interrupt status */
@@ -296,6 +320,35 @@
 	return IRQ_HANDLED;
 }
 
+static inline void sport_ndso_rx_read(struct sport_dev *dev)
+{
+	struct sport_config *cfg = &dev->config;
+	void *buf;
+
+	dev->regs->tcr1 |= TSPEN;
+	dev->regs->rcr1 |= RSPEN;
+	if (cfg->word_len <= 8)
+		while (dev->rx_received < dev->rx_len) {
+			dev->regs->tx16 = 0x00;
+			while (!(dev->regs->stat & RXNE))
+				cpu_relax();
+			buf = (void *)dev->rx_buf + dev->rx_received;
+			*(u8 *)buf = dev->regs->rx16;
+			dev->rx_received += 1;
+		}
+	else if (cfg->word_len <= 16)
+		while (dev->rx_received < dev->rx_len) {
+			dev->regs->tx16 = 0x0000;
+			while (!(dev->regs->stat & RXNE))
+				cpu_relax();
+			buf = (void *)dev->rx_buf + dev->rx_received;
+			*(u16 *)buf = dev->regs->rx16;
+			dev->rx_received += 2;
+		}
+	dev->regs->tcr1 &= ~TSPEN;
+	dev->regs->rcr1 &= ~RSPEN;
+}
+
 static inline void sport_rx_read(struct sport_dev *dev)
 {
 	struct sport_config *cfg = &dev->config;
@@ -337,6 +390,40 @@
 	return IRQ_HANDLED;
 }
 
+static inline void sport_ndso_tx_write(struct sport_dev *dev)
+{
+	struct sport_config *cfg = &dev->config;
+	void *buf;
+	int i, dummy;
+
+	dev->regs->tcr1 |= TSPEN;
+	dev->regs->rcr1 |= RSPEN;
+	for (i = 0; i < 50; i++) {
+		if (cfg->word_len <= 8)
+			while (dev->tx_sent < dev->tx_len) {
+				buf = (void *)dev->tx_buf + dev->tx_sent;
+				dev->regs->tx16 = *(u8 *)buf;
+				dev->tx_sent += 1;
+				while (!(dev->regs->stat & RXNE))
+					cpu_relax();
+				dummy = dev->regs->rx16;
+			}
+		else if (cfg->word_len <= 16) {
+			while (dev->tx_sent < dev->tx_len) {
+				buf = (void *)dev->tx_buf + dev->tx_sent;
+				dev->regs->tx16 = *(u16 *)buf;
+				dev->tx_sent += 2;
+				while (!(dev->regs->stat & RXNE))
+					cpu_relax();
+				dummy = dev->regs->rx16;
+			}
+			dev->tx_sent = 0;
+		}
+	}
+	dev->regs->tcr1 &= ~TSPEN;
+	dev->regs->rcr1 &= ~RSPEN;
+}
+
 static inline void sport_tx_write(struct sport_dev *dev)
 {
 	struct sport_config *cfg = &dev->config;
@@ -368,9 +455,10 @@
 {
 	struct sport_dev *dev = dev_id;
 
-	if (dev->tx_sent < dev->tx_len)
-		sport_tx_write(dev);
-
+	if (sport_mode != NDSO_MODE) {
+		if (dev->tx_sent < dev->tx_len)
+			sport_tx_write(dev);
+	}
 	if (dev->tx_len != 0 && dev->tx_sent >= dev->tx_len
 	    && dev->config.int_clk) {
 		unsigned int stat;
@@ -487,6 +575,8 @@
 		goto fail3;
 	}
 
+	sport_clkdiv = 0x24;
+	irq_notfreed = 1;
  done:
 	mutex_unlock(&dev->mutex);
 	return 0;
@@ -525,8 +615,11 @@
 		free_dma(dev->dma_rx_chan);
 		free_dma(dev->dma_tx_chan);
 	} else {
-		free_irq(dev->tx_irq, dev);
-		free_irq(dev->rx_irq, dev);
+		if (irq_notfreed) {
+			free_irq(dev->tx_irq, dev);
+			free_irq(dev->rx_irq, dev);
+			irq_notfreed = 0;
+		}
 	}
 	free_irq(dev->err_irq, dev);
 
@@ -585,6 +678,16 @@
 		dev->rx_received = 0;
 	}
 
+	if (sport_mode == NDSO_MODE) {
+		if (irq_notfreed) {
+			free_irq(dev->tx_irq, dev);
+			free_irq(dev->rx_irq, dev);
+			irq_notfreed = 0;
+		}
+		sport_ndso_rx_read(dev);
+		goto out;
+	}
+
 	dev->regs->rcr1 |= RSPEN;
 	SSYNC();
 
@@ -593,7 +696,7 @@
 		count = -ERESTARTSYS;
 		/* fall through */
 	}
-
+out:
 	pr_debug("Complete called in dma rx irq handler\n");
 	mutex_unlock(&dev->mutex);
 
@@ -647,9 +750,18 @@
 		dev->tx_buf = buf;
 		dev->tx_len = count;
 		dev->tx_sent = 0;
-
+		if (sport_mode == NDSO_MODE) {
+			if (irq_notfreed) {
+				free_irq(dev->tx_irq, dev);
+				free_irq(dev->rx_irq, dev);
+				irq_notfreed = 0;
+			}
+			sport_ndso_tx_write(dev);
+			goto out;
+		}
 		sport_tx_write(dev);
 	}
+
 	dev->regs->tcr1 |= TSPEN;
 	SSYNC();
 
@@ -660,7 +772,7 @@
 		/* fall through */
 	}
 	pr_debug("waiting over\n");
-
+out:
 	mutex_unlock(&dev->mutex);
 
 	return count;
@@ -671,7 +783,7 @@
 {
 	struct sport_dev *dev = filp->private_data;
 	struct sport_config config;
-
+	unsigned long value;
 	pr_debug("%s: enter, arg:0x%lx\n", __func__, arg);
 	switch (cmd) {
 	case SPORT_IOC_CONFIG:
@@ -681,6 +793,17 @@
 			return -EFAULT;
 		break;
 
+	case SPORT_IOC_GET_SYSTEMCLOCK:
+		value = get_sclk();
+		copy_to_user((unsigned long *)arg, &value, sizeof(unsigned long)) ? -EFAULT : 0;
+		break;
+
+	case SPORT_IOC_SET_BAUDRATE:
+		if (arg > (133000000 / 4))
+			return -EINVAL;
+		sport_clkdiv = hz_to_sport_clkdiv(arg);
+		break;
+
 	default:
 		return -EINVAL;
 	}
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to