[RFC] [PATCH 1/2] high speed uart driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds UART library support on top of serial.c. This gives us seemless resource management across multiple users.
Functionality of the library:
- Requesting UART
- Initial UART configuration
- Data transfer Configuration(DMA mode)
- ISR registration
- UART Speed change

Signed-off-by: Girish S G <girishsg@xxxxxx>
---
 arch/arm/mach-omap2/serial.c |  800 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 793 insertions(+), 7 deletions(-)

Index: linux-omap-dec10/arch/arm/mach-omap2/serial.c
===================================================================
--- linux-omap-dec10.orig/arch/arm/mach-omap2/serial.c	2007-12-17 16:56:27.000000000 +0530
+++ linux-omap-dec10/arch/arm/mach-omap2/serial.c	2007-12-17 19:39:10.150175975 +0530
@@ -17,12 +17,57 @@
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
-
+#include <linux/slab.h>
+#include <linux/serial.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/mach/irq.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/dma.h>
 #include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/serial.h>
+#include <asm/arch/omap-hsuart.h>
 
 #include <asm/arch/common.h>
 #include <asm/arch/board.h>
 
+#define CONSOLE_NAME    "console="
+#define FREE            0
+#define USED            1
+#define MAX_BUF_SIZE    12000
+
+/* structure for storing UART DMA info */
+struct omap_hsuart {
+	u8 uart_no;
+	int rx_dma_channel;
+	int tx_dma_channel;
+
+	u8 dma_tx;	/* DMA receive line */
+	u8 dma_rx;	/* DMA transmit line */
+
+	dma_addr_t rx_buf_dma_phys;	/* Physical adress of RX DMA buffer */
+	dma_addr_t tx_buf_dma_phys;	/* Physical adress of TX DMA buffer */
+
+	void *rx_buf_dma_virt;	/* Virtual adress of RX DMA buffer */
+	void *tx_buf_dma_virt;	/* Virtual adress of TX DMA buffer */
+
+	u8 tx_buf_state;
+	u8 rx_buf_state;
+
+	struct uart_callback cb;
+	u8 mode;
+
+	spinlock_t uart_lock;
+	int in_use;
+};
+
+static struct omap_hsuart ui[MAX_UARTS + 1];
+
 static struct clk * uart1_ick = NULL;
 static struct clk * uart1_fck = NULL;
 static struct clk * uart2_ick = NULL;
@@ -75,6 +120,725 @@
 }
 
 /*
+ * omap_hsuart_isr
+ * Identifes the source of interrupt(UART1, UART2, UART3)
+ * and reads respective IIR register data.
+ * Sends IIR data to the user driver.
+ */
+static irqreturn_t
+omap_hsuart_isr(int irq, void *hs_uart)
+{
+	struct omap_hsuart *hs = hs_uart;
+	struct plat_serial8250_port *p = serial_platform_data + hs->uart_no;
+	u8 lcr_data, iir_data;
+
+	lcr_data = serial_read_reg(p, UART_LCR);
+	serial_write_reg(p, UART_LCR, LCR_MODE1);
+
+	iir_data = serial_read_reg(p, UART_IIR);
+	/* Restore lcr data */
+	serial_write_reg(p, UART_LCR, lcr_data);
+
+	hs->cb.int_callback(iir_data, hs->cb.dev);
+
+	return IRQ_HANDLED;
+}
+
+static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	u8 uart_no = 0;
+
+	if (lch == ui[UART1].rx_dma_channel)
+		uart_no = UART1;
+	else if (lch == ui[UART2].rx_dma_channel)
+		uart_no = UART2;
+	else if (lch == ui[UART3].rx_dma_channel)
+		uart_no = UART3;
+
+	ui[uart_no].cb.uart_rx_dma_callback(lch, ch_status, data);
+	ui[uart_no].rx_buf_state = FREE;
+}
+
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	u8 uart_no = 0;
+
+	if (lch == ui[UART1].tx_dma_channel)
+		uart_no = UART1;
+	else if (lch == ui[UART2].tx_dma_channel)
+		uart_no = UART2;
+	else if (lch == ui[UART3].tx_dma_channel)
+		uart_no = UART3;
+
+	ui[uart_no].cb.uart_tx_dma_callback(lch, ch_status, data);
+	ui[uart_no].tx_buf_state = FREE;
+}
+
+/*
+ * omap_hsuart_get_parms
+ * reads requested register data
+ */
+int omap_hsuart_get_parms(u8 uart_no, u8 *data, u8 reg, u8 lcr_mode)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+	u8 lcr_data;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	lcr_data = serial_read_reg(p, UART_LCR);
+
+	serial_write_reg(p, UART_LCR, lcr_mode);
+	*data = serial_read_reg(p, reg);
+	/* Restore LCR data */
+	serial_write_reg(p, UART_LCR, lcr_data);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_get_parms);
+
+/*
+ * omap_hsuart_set_parms
+ * writes values into requested UART register
+ */
+int omap_hsuart_set_parms(u8 uart_no, struct uart_setparm *uart_set)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+	u8 lcr_data;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock(&(ui[uart_no].uart_lock));
+
+	lcr_data = serial_read_reg(p, UART_LCR);
+
+	serial_write_reg(p, UART_LCR, uart_set->lcr);
+	serial_write_reg(p, uart_set->reg, uart_set->reg_data);
+
+	/* Restore LCR data */
+	serial_write_reg(p, UART_LCR, lcr_data);
+
+	spin_unlock(&(ui[uart_no].uart_lock));
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_set_parms);
+
+/*
+ * omap_hsuart_get_speed
+ * reads DLL and DLH register values and
+ * calculates UART speed.
+ */
+int omap_hsuart_get_speed(u8 uart_no, int *speed)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+	u8 reg = 0;
+	u8 dll, dlh;
+	u16 divisor = 0;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock(&(ui[uart_no].uart_lock));
+	reg = LCR_MODE2;
+	serial_write_reg(p, UART_LCR, reg);
+	dll = serial_read_reg(p, UART_DLL);
+	dlh = serial_read_reg(p, UART_DLM);
+
+	divisor = (dlh << 8) + dll;
+
+	if (!divisor) {
+		printk(KERN_WARNING "DLL and DLH read error\n");
+		spin_unlock(&(ui[uart_no].uart_lock));
+		return -EPERM;
+	}
+
+	*speed = (BASE_CLK) / 16 * divisor;
+	spin_unlock(&(ui[uart_no].uart_lock));
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_get_speed);
+
+/*
+ * omap_hsuart_set_speed
+ * used to set the UART speed.
+ */
+int omap_hsuart_set_speed(u8 uart_no, int speed)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+	u8 lcr_data, mdr1_data;
+	int divisor = 0;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock(&(ui[uart_no].uart_lock));
+	/* Disable UART before changing the clock speed - TRM - 18-52 */
+	mdr1_data = serial_read_reg(p, UART_OMAP_MDR1);
+	serial_write_reg(p, UART_OMAP_MDR1, ~MODE_SELECT_MASK);
+
+	/* Enable access to DLL and DLH registers */
+	lcr_data = serial_read_reg(p, UART_LCR);
+	serial_write_reg(p, UART_LCR, LCR_MODE2);
+
+	mdr1_data &= MODE_SELECT_MASK;
+
+	/* Only UART3 supports IrDA mode */
+	if ((uart_no == UART3) && (ui[uart_no].mode == IRDA_MODE)) {
+		if (speed <= IR_SIR_SPEED) {
+			divisor = BASE_CLK / (16 * speed);
+			mdr1_data |= UART_SIR_MODE;
+		} else if (speed <= IR_MIR_SPEED) {
+			divisor = BASE_CLK / (41 * speed);
+			mdr1_data |= UART_MIR_MODE;
+		} else if (speed <= IR_FIR_SPEED)
+			mdr1_data |= UART_FIR_MODE;
+		else
+			goto exit_path1;
+	} else if (ui[uart_no].mode == UART_MODE) {
+		if (speed <= UART_16X_SPEED) {
+			divisor = BASE_CLK / (16 * speed);
+			mdr1_data |= UART_16X_MODE;
+		} else if (speed <= UART_13X_SPEED) {
+			divisor = BASE_CLK / (13 * speed);
+			mdr1_data |= UART_13X_MODE;
+		} else
+			goto exit_path1;
+	} else if (ui[uart_no].mode == UART_AUTOBAUD_MODE)
+		mdr1_data |= UART_16XAUTO_MODE;
+	else if (ui[uart_no].mode == CIR_MODE)
+		mdr1_data |= UART_CIR_MODE;
+	else
+		goto exit_path1;
+
+	serial_write_reg(p, UART_DLL, divisor & 0xFF);
+	serial_write_reg(p, UART_DLM, divisor >> 8);
+	serial_write_reg(p, UART_OMAP_MDR1, mdr1_data);
+
+	printk(KERN_DEBUG "Changing UART speed to %d....\n", speed);
+
+	/* restore LCR values */
+	serial_write_reg(p, UART_LCR, lcr_data);
+	spin_unlock(&(ui[uart_no].uart_lock));
+	return 0;
+
+exit_path1:
+	printk(KERN_ERR "Requested speed is not supported\n");
+	/* Restore LCR and MDR1 regisgters to original value */
+	serial_write_reg(p, UART_OMAP_MDR1, mdr1_data);
+	serial_write_reg(p, UART_LCR, lcr_data);
+	spin_unlock(&(ui[uart_no].uart_lock));
+	return -EPERM;
+}
+EXPORT_SYMBOL(omap_hsuart_set_speed);
+
+/*
+ * omap_hsuart_config
+ * configures the requested UART
+ */
+int omap_hsuart_config(u8 uart_no, struct uart_config *uartcfg)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+
+	if (in_interrupt())
+		BUG();
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock(&(ui[uart_no].uart_lock));
+
+	ui[uart_no].mode = uartcfg->mode;
+
+	/* Put UART3 in reset mode */
+	serial_write_reg(p, UART_OMAP_MDR1, ~MODE_SELECT_MASK);
+
+	/* Clear DLL and DLH */
+	serial_write_reg(p, UART_LCR, LCR_MODE2);
+	serial_write_reg(p, UART_DLL, 0);
+	serial_write_reg(p, UART_DLM, 0);
+
+	serial_write_reg(p, UART_OMAP_SCR, 0);
+
+	serial_write_reg(p, UART_LCR, LCR_MODE3);
+	serial_write_reg(p, UART_EFR, (uartcfg->efr));
+
+	serial_write_reg(p, UART_LCR, LCR_MODE2);
+	/* enable TCR and TLR Registers */
+	serial_write_reg(p, UART_MCR, MCR_TCR_TLR);
+
+	serial_write_reg(p, UART_TI752_TLR, (uartcfg->tlr));
+
+	serial_write_reg(p, UART_LCR, (uartcfg->lcr));
+
+	serial_write_reg(p, UART_FCR, (uartcfg->fcr));
+
+	/* disable access to TCR and TLR registers */
+	serial_write_reg(p, UART_MCR, 0);
+
+	serial_write_reg(p, UART_OMAP_SCR, (uartcfg->scr));
+
+	serial_write_reg(p, UART_OMAP_MDR1, (uartcfg->mdr1));
+
+	serial_write_reg(p, UART_OMAP_MDR2, (uartcfg->mdr2));
+
+	serial_write_reg(p, UART_OMAP_ACREG, (uartcfg->acreg));
+
+	serial_write_reg(p, UART_IER, (uartcfg->ier));
+
+	if (ui[uart_no].mode == IRDA_MODE) {
+		serial_write_reg(p, UART_OMAP_RXFLL, (uartcfg->rxfll));
+		serial_write_reg(p, UART_OMAP_RXFLH, (uartcfg->rxflh));
+	}
+	serial_read_reg(p, UART_OMAP_RESUME);
+	spin_unlock(&(ui[uart_no].uart_lock));
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_config);
+
+/* omap_hsuart_stop stops/resets requested UART. */
+int omap_hsuart_stop(u8 uart_no)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+
+	if (in_interrupt())
+		BUG();
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock(&(ui[uart_no].uart_lock));
+	/* Put UART3 in reset mode */
+	serial_write_reg(p, UART_OMAP_MDR1, ~MODE_SELECT_MASK);
+
+	/* Clear DLL and DLH */
+	serial_write_reg(p, UART_LCR, LCR_MODE2);
+	serial_write_reg(p, UART_DLL, 0);
+	serial_write_reg(p, UART_DLM, 0);
+
+	/* Disable requested UART interrupts */
+	serial_write_reg(p, UART_IER, 0);
+
+	/* Stop DMA channels */
+	omap_stop_dma(ui[uart_no].rx_dma_channel);
+	omap_stop_dma(ui[uart_no].tx_dma_channel);
+
+	/* Move buffer states to free */
+	ui[uart_no].tx_buf_state = FREE;
+	ui[uart_no].rx_buf_state = FREE;
+
+	spin_unlock(&(ui[uart_no].uart_lock));
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_stop);
+
+/* omap_hsuart_rx Copies data from DMA buffer to user driver buffer. */
+int omap_hsuart_rx(u8 uart_no, void *data, int *len)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock_irqsave(&(ui[uart_no].uart_lock), flags);
+	*len = omap_get_dma_dst_pos(ui[uart_no].rx_dma_channel);
+	*len -= ui[uart_no].rx_buf_dma_phys;
+
+	memcpy(data, ui[uart_no].rx_buf_dma_virt, *len);
+	/* DMA data is copied to user driver buffer,
+	 * now it is safe to move rx_buf_state to free.
+	 */
+	ui[uart_no].rx_buf_state = FREE;
+
+	spin_unlock_irqrestore(&(ui[uart_no].uart_lock), flags);
+	return ret;
+}
+EXPORT_SYMBOL(omap_hsuart_rx);
+
+/* omap_hsuart_tx copies data from client driver buffer to DMA buffer. */
+int omap_hsuart_tx(u8 uart_no, void *data, int size)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	if (unlikely(size < 0 || size > ui[uart_no].cb.tx_buf_size)) {
+		printk(KERN_DEBUG "omap_hsuart: Error.Invalid buffer size\n");
+		return -EPERM;
+	}
+	spin_lock_irqsave(&(ui[uart_no].uart_lock), flags);
+	printk(KERN_DEBUG "omap_hsuart:"
+				"omap_hsuart_tx:%s\n %d\n", (char *)data, size);
+	memcpy(ui[uart_no].tx_buf_dma_virt, data, size);
+
+	spin_unlock_irqrestore(&(ui[uart_no].uart_lock), flags);
+	return ret;
+}
+EXPORT_SYMBOL(omap_hsuart_tx);
+
+/*  omap_hsuart_start_tx - starts TX of data using DMA or PIO */
+int omap_hsuart_start_tx(u8 uart_no, int size)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	if (ui[uart_no].tx_buf_state == USED) {
+		printk(KERN_DEBUG "omap_hsuart: UART DMA buffer is not free\n");
+		return -EBUSY;
+	}
+
+	ui[uart_no].tx_buf_state = USED;
+
+	omap_set_dma_dest_params(ui[uart_no].tx_dma_channel, 0,
+				 OMAP_DMA_AMODE_CONSTANT, p->mapbase, 0,
+				 0);
+	omap_set_dma_src_params(ui[uart_no].tx_dma_channel, 0,
+				OMAP_DMA_AMODE_POST_INC,
+				ui[uart_no].tx_buf_dma_phys, 0, 0);
+	omap_set_dma_transfer_params(ui[uart_no].tx_dma_channel,
+				     OMAP_DMA_DATA_TYPE_S8, size, 1,
+				     OMAP_DMA_SYNC_ELEMENT,
+				     ui[uart_no].dma_tx, 0);
+	omap_start_dma(ui[uart_no].tx_dma_channel);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_start_tx);
+
+/* Starts receiving data from DMA rx channel */
+int omap_hsuart_start_rx(u8 uart_no, int size)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	if (ui[uart_no].rx_buf_state == USED) {
+		printk(KERN_DEBUG "omap_hsuart: UART DMA buffer is not free\n");
+		return -EBUSY;
+	}
+
+	ui[uart_no].rx_buf_state = USED;
+
+	omap_set_dma_src_params(ui[uart_no].rx_dma_channel, 0,
+				OMAP_DMA_AMODE_CONSTANT, p->mapbase, 0,
+				0);
+	omap_set_dma_dest_params(ui[uart_no].rx_dma_channel, 0,
+					OMAP_DMA_AMODE_POST_INC,
+					ui[uart_no].rx_buf_dma_phys, 0,
+					0);
+
+	omap_set_dma_transfer_params(ui[uart_no].rx_dma_channel,
+					OMAP_DMA_DATA_TYPE_S8, size, 1,
+					OMAP_DMA_SYNC_ELEMENT,
+					ui[uart_no].dma_rx, 0);
+	omap_start_dma(ui[uart_no].rx_dma_channel);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_start_rx);
+
+/* omap_hsuart_stop_rx : stops rx dma */
+int omap_hsuart_stop_rx(u8 uart_no)
+{
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	omap_stop_dma(ui[uart_no].rx_dma_channel);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_stop_rx);
+
+/* omap_hsuart_stop_tx : stops tx dma */
+int omap_hsuart_stop_tx(u8 uart_no)
+{
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	omap_stop_dma(ui[uart_no].tx_dma_channel);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_stop_tx);
+
+/*  omap_hsuart_interrupt used to enable/disable UART interrupts */
+int omap_hsuart_interrupt(u8 uart_no, int enable)
+{
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	if (enable)
+		enable_irq(p->irq);
+	else
+		disable_irq(p->irq);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_interrupt);
+
+/*  omap_hsuart_request Allocates requested UART.*/
+int omap_hsuart_request(u8 uart_no, struct uart_callback *uart_cback)
+{
+	int err;
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+	struct uart_callback *cb = uart_cback;
+	struct omap_hsuart *hs = &ui[uart_no];
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock(&(hs->uart_lock));
+	if (ui[uart_no].in_use) {
+		printk(KERN_DEBUG
+		       "Err Requested UART is not available\n");
+		spin_unlock(&(ui[uart_no].uart_lock));
+		return -EACCES;
+	}
+	spin_unlock(&(hs->uart_lock));
+
+	serial8250_unregister_port(uart_no);
+
+	switch (uart_no) {
+	case UART1:
+		hs->dma_tx = OMAP24XX_DMA_UART1_TX;
+		hs->dma_rx = OMAP24XX_DMA_UART1_RX;
+		break;
+	case UART2:
+		hs->dma_tx = OMAP24XX_DMA_UART2_TX;
+		hs->dma_rx = OMAP24XX_DMA_UART2_RX;
+		break;
+	case UART3:
+		hs->dma_tx = OMAP24XX_DMA_UART3_TX;
+		hs->dma_rx = OMAP24XX_DMA_UART3_RX;
+		break;
+	default:
+		return -EPERM;
+	}
+
+
+	if ((hs->cb.txrx_req_flag == TXRX)
+	    || (hs->cb.txrx_req_flag == RX_ONLY)) {
+		if (unlikely(cb->rx_buf_size < 1 ||
+			cb->rx_buf_size > MAX_BUF_SIZE)) {
+			printk(KERN_DEBUG
+				 "omap_hsuart: Err Invalid RX buffer size\n");
+			return -EACCES;
+		}
+	}
+
+	if ((hs->cb.txrx_req_flag == TXRX)
+	    || (hs->cb.txrx_req_flag == TX_ONLY)) {
+		if (unlikely(cb->tx_buf_size < 1 ||
+			cb->tx_buf_size > MAX_BUF_SIZE)) {
+			printk(KERN_DEBUG
+				 "omap_hsuart: Err Invalid TX buffer size\n");
+			return -EACCES;
+		}
+	}
+
+	hs->uart_no = uart_no;
+	hs->cb.dev = cb->dev;
+	hs->cb.int_callback = cb->int_callback;
+	hs->cb.dev_name = cb->dev_name;
+
+	if (request_irq(p->irq, (void *)omap_hsuart_isr, 0,
+		hs->cb.dev_name, hs)) {
+		printk(KERN_ERR "omap_hsuart: Error: IRQ allocation failed\n");
+		err = -EPERM;
+		goto exit_path0;
+	}
+
+	spin_lock(&(hs->uart_lock));
+	hs->cb.txrx_req_flag = cb->txrx_req_flag;
+
+	if ((hs->cb.txrx_req_flag == TXRX)
+	    || (hs->cb.txrx_req_flag == RX_ONLY)) {
+		/* Request DMA Channels for requested UART */
+		err = omap_request_dma(hs->dma_rx,
+			 "UART Rx DMA", (void *)uart_rx_dma_callback,
+			 hs->cb.dev, &(hs->rx_dma_channel));
+		if (err) {
+			printk(KERN_ERR
+				 "omap_hsuart: Failed to get DMA Channels\n");
+			goto exit_path1;
+		}
+
+		hs->cb.rx_buf_size = cb->rx_buf_size;
+		hs->cb.uart_rx_dma_callback =
+		    cb->uart_rx_dma_callback;
+		hs->rx_buf_dma_virt =
+		    dma_alloc_coherent(NULL, hs->cb.rx_buf_size,
+				       (dma_addr_t *) &
+					(hs->rx_buf_dma_phys), 0);
+		if (!hs->rx_buf_dma_virt) {
+			printk(KERN_ERR
+			       "Failed to allocate DMA Rx Buffer...!!!!\n");
+			goto exit_path2;
+		}
+	}
+
+	if ((hs->cb.txrx_req_flag == TXRX)
+	    || (hs->cb.txrx_req_flag == TX_ONLY)) {
+		err = omap_request_dma(hs->dma_tx,
+			 "UART Tx DMA", (void *)uart_tx_dma_callback,
+			 hs->cb.dev, &(hs->tx_dma_channel));
+		if (err) {
+			printk(KERN_ERR
+				 "omap_hsuart: Failed to get DMA Channels\n");
+			goto exit_path3;
+		}
+		hs->cb.tx_buf_size = cb->tx_buf_size;
+		hs->cb.uart_tx_dma_callback =
+		    cb->uart_tx_dma_callback;
+		hs->tx_buf_dma_virt =
+		    dma_alloc_coherent(NULL, hs->cb.tx_buf_size,
+					(dma_addr_t *) &
+					(hs->tx_buf_dma_phys), 0);
+		if (!hs->tx_buf_dma_virt) {
+			printk(KERN_ERR
+			       "omap_hsuart: Failed to allocate DMA Tx Buf\n");
+			goto exit_path4;
+		}
+	}
+
+	hs->tx_buf_state = FREE;
+	hs->rx_buf_state = FREE;
+
+	hs->in_use = 1;
+	spin_unlock(&(hs->uart_lock));
+
+	return 0;
+
+exit_path4:
+	omap_free_dma(hs->rx_dma_channel);
+	if ((hs->cb.txrx_req_flag == TXRX)
+	    || (hs->cb.txrx_req_flag == TX_ONLY)) {
+		hs->cb.tx_buf_size = 0;
+		hs->cb.uart_tx_dma_callback = NULL;
+	}
+
+exit_path3:
+	if ((hs->cb.txrx_req_flag == TXRX)
+	    || (hs->cb.txrx_req_flag == RX_ONLY)) {
+		dma_free_coherent(hs->cb.dev,
+				  hs->cb.rx_buf_size,
+				  hs->rx_buf_dma_virt,
+				  hs->rx_buf_dma_phys);
+		hs->cb.rx_buf_size = 0;
+		hs->cb.uart_rx_dma_callback = NULL;
+
+	}
+exit_path2:
+	if (hs->cb.txrx_req_flag == TXRX
+	    || (hs->cb.txrx_req_flag == RX_ONLY))
+		omap_free_dma(hs->rx_dma_channel);
+exit_path1:
+	free_irq(p->irq, hs);
+exit_path0:
+	hs->cb.dev = NULL;
+	hs->cb.int_callback = NULL;
+	spin_unlock(&(hs->uart_lock));
+
+	return err;
+}
+EXPORT_SYMBOL(omap_hsuart_request);
+
+/* Release the requested uart */
+int omap_hsuart_release(u8 uart_no)
+{
+	struct omap_hsuart *hs = &ui[uart_no];
+	struct plat_serial8250_port *p = serial_platform_data + uart_no;
+
+	if (uart_no > MAX_UARTS)
+		return -ENODEV;
+
+	spin_lock(&(ui[uart_no].uart_lock));
+	if (!hs->in_use) {
+		printk(KERN_DEBUG
+			 "omap_hsuart: Requested UART already in free state\n");
+		spin_unlock(&(hs->uart_lock));
+		return -EACCES;
+	}
+	/* MOVE requested UART to free state.
+	 * Free DMA channels.
+	 * Free DMA buffers.
+	 */
+	free_irq(p->irq, hs);
+
+	omap_free_dma(hs->rx_dma_channel);
+	omap_free_dma(hs->tx_dma_channel);
+
+	dma_free_coherent(hs->cb.dev,
+			hs->cb.rx_buf_size,
+			hs->rx_buf_dma_virt,
+			hs->rx_buf_dma_phys);
+	dma_free_coherent(ui[uart_no].cb.dev,
+			hs->cb.tx_buf_size,
+			hs->tx_buf_dma_virt,
+			hs->tx_buf_dma_phys);
+	hs->cb.uart_tx_dma_callback = NULL;
+	hs->cb.uart_rx_dma_callback = NULL;
+
+	hs->cb.int_callback = NULL;
+	hs->cb.dev_name = NULL;
+	hs->cb.dev = NULL;
+	hs->in_use = 0;
+
+	hs->rx_dma_channel = 0;
+	hs->tx_dma_channel = 0;
+	hs->rx_buf_dma_phys = 0;
+	hs->tx_buf_dma_phys = 0;
+	hs->rx_buf_dma_virt = NULL;
+	hs->tx_buf_dma_virt = NULL;
+	hs->rx_buf_state = 0;
+	hs->tx_buf_state = 0;
+
+	spin_unlock(&(hs->uart_lock));
+	return 0;
+}
+EXPORT_SYMBOL(omap_hsuart_release);
+
+/* console_detect Detect: Console UART using command line parameter. */
+int console_detect(char *str)
+{
+	char *next, *start = NULL;
+	int i;
+
+	i = strlen(CONSOLE_NAME);
+	next = saved_command_line;
+	while ((next = strchr(next, 'c')) != NULL) {
+		if (!strncmp(next, CONSOLE_NAME, i)) {
+			start = next;
+			break;
+		} else
+			next++;
+
+	}
+	if (!start)
+		return -EPERM;
+	i = 0;
+	start = strchr(start, '=') + 1;
+	while (*start != ',') {
+		str[i++] = *start++;
+		if (i > 6) {
+			printk(KERN_DEBUG
+				 "omap_hsuart: Invalid Console Name\n");
+			return -EPERM;
+		}
+	}
+	str[i] = '\0';
+
+	return 0;
+}
+
+/*
  * Internal UARTs need to be initialized for the 8250 autoconfig to work
  * properly. Note that the TX watermark initialization may not be needed
  * once the 8250.c watermark handling code is merged.
@@ -90,6 +854,7 @@
 void __init omap_serial_init(void)
 {
 	int i;
+	char str[7];
 	const struct omap_uart_config *info;
 
 	/*
@@ -116,39 +881,39 @@
 		case 0:
 			uart1_ick = clk_get(NULL, "uart1_ick");
 			if (IS_ERR(uart1_ick))
-				printk("Could not get uart1_ick\n");
+				printk(KERN_ERR "Could not get uart1_ick\n");
 			else
 				clk_enable(uart1_ick);
 
 			uart1_fck = clk_get(NULL, "uart1_fck");
 			if (IS_ERR(uart1_fck))
-				printk("Could not get uart1_fck\n");
+				printk(KERN_ERR "Could not get uart1_fck\n");
 			else
 				clk_enable(uart1_fck);
 			break;
 		case 1:
 			uart2_ick = clk_get(NULL, "uart2_ick");
 			if (IS_ERR(uart2_ick))
-				printk("Could not get uart2_ick\n");
+				printk(KERN_ERR "Could not get uart2_ick\n");
 			else
 				clk_enable(uart2_ick);
 
 			uart2_fck = clk_get(NULL, "uart2_fck");
 			if (IS_ERR(uart2_fck))
-				printk("Could not get uart2_fck\n");
+				printk(KERN_ERR "Could not get uart2_fck\n");
 			else
 				clk_enable(uart2_fck);
 			break;
 		case 2:
 			uart3_ick = clk_get(NULL, "uart3_ick");
 			if (IS_ERR(uart3_ick))
-				printk("Could not get uart3_ick\n");
+				printk(KERN_ERR "Could not get uart3_ick\n");
 			else
 				clk_enable(uart3_ick);
 
 			uart3_fck = clk_get(NULL, "uart3_fck");
 			if (IS_ERR(uart3_fck))
-				printk("Could not get uart3_fck\n");
+				printk(KERN_ERR "Could not get uart3_fck\n");
 			else
 				clk_enable(uart3_fck);
 			break;
@@ -156,6 +921,27 @@
 
 		omap_serial_reset(p);
 	}
+
+	/* initialize tx/rx channel */
+	for (i = UART1; i <= UART3; i++) {
+		ui[i].rx_dma_channel = -1;
+		ui[i].tx_dma_channel = -1;
+	}
+
+	/* Reserve the console uart */
+	if (console_detect(str))
+		printk(KERN_DEBUG "omap_hsuart: Invalid console paramter"
+			"UART Library Init Failed\n");
+
+	if (!strcmp(str, "ttyS0"))
+		ui[UART1].in_use = 1;
+	else if (!strcmp(str, "ttyS1"))
+		ui[UART2].in_use = 1;
+	else if (!strcmp(str, "ttyS2"))
+		ui[UART3].in_use = 1;
+	else
+		printk(KERN_DEBUG
+			"Unable to recongnize Console UART\n");
 }
 
 static struct platform_device serial_device = {

-
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux