[PATCH 1/2] serial/imx: add DMA support

Russell King - ARM Linux linux at arm.linux.org.uk
Thu Apr 26 07:11:16 EDT 2012


On Thu, Apr 26, 2012 at 06:37:11PM +0800, Huang Shijie wrote:
> Add the DMA support for uart RX and TX.
> 
> Signed-off-by: Huang Shijie <b32955 at freescale.com>
> ---

Apart from the comments below,

1. How do you deal with transmitting the high-priority XON/XOFF
   characters (port->x_char) which occur with s/w flow control and
   the tty buffers fill up?
2. How do you deal with flow control in general?  IOW, what happens
   when the remote end deasserts your CTS with h/w flow control enabled.
   How does your end deal with sending RTS according to flow control
   conditions?

>  .../bindings/tty/serial/fsl-imx-uart.txt           |    7 +
>  drivers/tty/serial/imx.c                           |  386 +++++++++++++++++++-
>  2 files changed, 389 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
> index a9c0406..f27489d 100644
> --- a/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
> +++ b/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
> @@ -8,6 +8,10 @@ Required properties:
>  Optional properties:
>  - fsl,uart-has-rtscts : Indicate the uart has rts and cts
>  - fsl,irda-mode : Indicate the uart supports irda mode
> +- fsl,enable-dma : Indicate the uart supports DMA
> +- fsl,uart-dma-events : contains the DMA events for RX and TX,
> +	          The first is the RX event, while the other is TX.
> +- fsl,enable-dte: Indicate the uart works in DTE mode
>  
>  Example:
>  
> @@ -16,4 +20,7 @@ uart at 73fbc000 {
>  	reg = <0x73fbc000 0x4000>;
>  	interrupts = <31>;
>  	fsl,uart-has-rtscts;
> +	fsl,enable-dma;
> +	fsl,uart-dma-events = <xx xx>;
> +	fsl,enable-dte;
>  };
> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
> index e7fecee..65ba24d 100644
> --- a/drivers/tty/serial/imx.c
> +++ b/drivers/tty/serial/imx.c
> @@ -47,9 +47,11 @@
>  #include <linux/slab.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
> +#include <linux/dma-mapping.h>
>  
>  #include <asm/io.h>
>  #include <asm/irq.h>
> +#include <mach/dma.h>
>  #include <mach/imx-uart.h>
>  
>  /* Register definitions */
> @@ -82,6 +84,7 @@
>  #define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
>  #define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
>  #define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
> +#define  UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */
>  #define  UCR1_RRDYEN     (1<<9)	 /* Recv ready interrupt enable */
>  #define  UCR1_RDMAEN     (1<<8)	 /* Recv ready DMA enable */
>  #define  UCR1_IREN       (1<<7)	 /* Infrared interface enable */
> @@ -125,6 +128,7 @@
>  #define  UCR4_ENIRI 	 (1<<8)  /* Serial infrared interrupt enable */
>  #define  UCR4_WKEN  	 (1<<7)  /* Wake interrupt enable */
>  #define  UCR4_REF16 	 (1<<6)  /* Ref freq 16 MHz */
> +#define  UCR4_IDDMAEN    (1<<6)  /* DMA IDLE Condition Detected */
>  #define  UCR4_IRSC  	 (1<<5)  /* IR special case */
>  #define  UCR4_TCEN  	 (1<<3)  /* Transmit complete interrupt enable */
>  #define  UCR4_BKEN  	 (1<<2)  /* Break condition interrupt enable */
> @@ -134,6 +138,7 @@
>  #define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
>  #define  UFCR_RFDIV_REG(x)	(((x) < 7 ? 6 - (x) : 6) << 7)
>  #define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
> +#define  UFCR_DCEDTE	 (1<<6)
>  #define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
>  #define  USR1_RTSS  	 (1<<14) /* RTS pin status */
>  #define  USR1_TRDY  	 (1<<13) /* Transmitter ready interrupt/dma flag */
> @@ -200,12 +205,27 @@ struct imx_port {
>  	unsigned int		old_status;
>  	int			txirq,rxirq,rtsirq;
>  	unsigned int		have_rtscts:1;
> +	unsigned int		enable_dte:1;
> +	unsigned int		enable_dma:1;
>  	unsigned int		use_irda:1;
>  	unsigned int		irda_inv_rx:1;
>  	unsigned int		irda_inv_tx:1;
>  	unsigned short		trcv_delay; /* transceiver delay */
>  	struct clk		*clk;
>  	struct imx_uart_data	*devdata;
> +
> +	/* DMA fields */
> +	unsigned int		dma_req_rx;
> +	unsigned int		dma_req_tx;
> +	struct imx_dma_data	dma_data;
> +	struct dma_chan		*dma_chan_rx, *dma_chan_tx;
> +	struct scatterlist	rx_sgl, tx_sgl[2];
> +	void			*rx_buf;
> +	unsigned int		rx_bytes, tx_bytes;
> +	struct work_struct	tsk_dma_rx, tsk_dma_tx;

Why do you need a work struct to deal with DMA?

> +	unsigned int		dma_tx_nents;
> +	bool			dma_is_rxing;
> +	wait_queue_head_t	dma_wait;
>  };
>  
>  struct imx_port_ucrs {
> @@ -394,6 +414,13 @@ static void imx_stop_rx(struct uart_port *port)
>  	struct imx_port *sport = (struct imx_port *)port;
>  	unsigned long temp;
>  
> +	/*
> +	 * We are maybe in the SMP now, so if the DMA RX thread is running,
> +	 * we have to wait for it to finish.
> +	 */
> +	if (sport->enable_dma && sport->dma_is_rxing)
> +		return;
> +
>  	temp = readl(sport->port.membase + UCR2);
>  	writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
>  }
> @@ -429,6 +456,80 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
>  		imx_stop_tx(&sport->port);
>  }
>  
> +static void dma_tx_callback(void *data)
> +{
> +	struct imx_port *sport = data;
> +	struct scatterlist *sgl = &sport->tx_sgl[0];

	struct scatterlist *sgl = sport->tx_sgl;

is equivalent, and less typing.

> +	struct circ_buf *xmit = &sport->port.state->xmit;
> +
> +	dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
> +
> +	/* update the stat */
> +	spin_lock(&sport->port.lock);
> +	xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
> +	sport->port.icount.tx += sport->tx_bytes;
> +	spin_unlock(&sport->port.lock);

Callbacks are called from tasklet context, and will have IRQs enabled.
As the port lock is taken from IRQ context, this is waiting for a deadlock
to happen.  Have you run this with lockdep enabled?

> +
> +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +		uart_write_wakeup(&sport->port);
> +	schedule_work(&sport->tsk_dma_tx);
> +}
> +
> +static void dma_tx_work(struct work_struct *w)
> +{
> +	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
> +	struct circ_buf *xmit = &sport->port.state->xmit;
> +	struct scatterlist *sgl = &sport->tx_sgl[0];
> +	struct dma_async_tx_descriptor *desc;
> +	struct dma_chan	*chan = sport->dma_chan_tx;
> +	enum dma_status status;
> +	unsigned long flags;
> +	int ret;
> +
> +	status = chan->device->device_tx_status(chan, (dma_cookie_t)NULL, NULL);

Cookies aren't pointers.  NULL is inappropriate here.

> +	if (DMA_IN_PROGRESS == status)
> +		return;
> +
> +	spin_lock_irqsave(&sport->port.lock, flags);
> +	sport->tx_bytes = uart_circ_chars_pending(xmit);
> +	if (sport->tx_bytes > 0) {
> +		if (xmit->tail > xmit->head) {
> +			sport->dma_tx_nents = 2;
> +			sg_init_table(sgl, 2);
> +			sg_set_buf(sgl, xmit->buf + xmit->tail,
> +					UART_XMIT_SIZE - xmit->tail);
> +			sg_set_buf(&sgl[1], xmit->buf, xmit->head);
> +		} else {
> +			sport->dma_tx_nents = 1;
> +			sg_init_one(sgl, xmit->buf + xmit->tail,
> +					sport->tx_bytes);
> +		}
> +		spin_unlock_irqrestore(&sport->port.lock, flags);
> +
> +		ret = dma_map_sg(sport->port.dev, sgl,
> +				sport->dma_tx_nents, DMA_TO_DEVICE);
> +		if (ret == 0) {
> +			pr_err("DMA mapping error for TX.\n");
> +			return;
> +		}
> +		desc = dmaengine_prep_slave_sg(chan, sgl,
> +				sport->dma_tx_nents, DMA_MEM_TO_DEV, 0);

If you're setting a callback, you should set DMA_PREP_INTERRUPT in the
flags too.

> +		if (!desc) {
> +			pr_err("We cannot prepare for the TX slave dma!\n");
> +			return;
> +		}
> +		desc->callback = dma_tx_callback;
> +		desc->callback_param = sport;
> +
> +		/* fire it */
> +		dmaengine_submit(desc);
> +		dma_async_issue_pending(chan);
> +		return;
> +	}
> +	spin_unlock_irqrestore(&sport->port.lock, flags);
> +	return;
> +}
> +
>  /*
>   * interrupts disabled on entry
>   */
> @@ -448,8 +549,10 @@ static void imx_start_tx(struct uart_port *port)
>  		writel(temp, sport->port.membase + UCR1);
>  	}
>  
> -	temp = readl(sport->port.membase + UCR1);
> -	writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
> +	if (!sport->enable_dma) {
> +		temp = readl(sport->port.membase + UCR1);
> +		writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
> +	}
>  
>  	if (USE_IRDA(sport)) {
>  		temp = readl(sport->port.membase + UCR1);
> @@ -461,6 +564,11 @@ static void imx_start_tx(struct uart_port *port)
>  		writel(temp, sport->port.membase + UCR4);
>  	}
>  
> +	if (sport->enable_dma) {
> +		schedule_work(&sport->tsk_dma_tx);
> +		return;
> +	}
> +
>  	if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
>  		imx_transmit_buffer(sport);
>  }
> @@ -577,6 +685,28 @@ out:
>  	return IRQ_HANDLED;
>  }
>  
> +/*
> + * We wait for the RXFIFO is filled with some data, and then
> + * arise a DMA operation to receive the data.
> + */
> +static void imx_dma_rxint(struct imx_port *sport)
> +{
> +	unsigned long temp;
> +
> +	temp = readl(sport->port.membase + USR2);
> +	if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
> +		sport->dma_is_rxing = true;
> +
> +		/* disable the `Recerver Ready Interrrupt` */
> +		temp = readl(sport->port.membase + UCR1);
> +		temp &= ~(UCR1_RRDYEN);
> +		writel(temp, sport->port.membase + UCR1);
> +
> +		/* tell the DMA to receive the data. */
> +		schedule_work(&sport->tsk_dma_rx);
> +	}
> +}
> +
>  static irqreturn_t imx_int(int irq, void *dev_id)
>  {
>  	struct imx_port *sport = dev_id;
> @@ -584,8 +714,12 @@ static irqreturn_t imx_int(int irq, void *dev_id)
>  
>  	sts = readl(sport->port.membase + USR1);
>  
> -	if (sts & USR1_RRDY)
> -		imx_rxint(irq, dev_id);
> +	if (sts & USR1_RRDY) {
> +		if (sport->enable_dma)
> +			imx_dma_rxint(sport);
> +		else
> +			imx_rxint(irq, dev_id);
> +	}
>  
>  	if (sts & USR1_TRDY &&
>  			readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
> @@ -685,6 +819,195 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
>  	return 0;
>  }
>  
> +static bool imx_uart_filter(struct dma_chan *chan, void *param)
> +{
> +	struct imx_port *sport = param;
> +
> +	if (!imx_dma_is_general_purpose(chan))
> +		return false;
> +	chan->private = &sport->dma_data;
> +	return true;
> +}
> +
> +#define RX_BUF_SIZE	(PAGE_SIZE)
> +static int start_rx_dma(struct imx_port *sport);
> +static void dma_rx_work(struct work_struct *w)
> +{
> +	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx);
> +	struct tty_struct *tty = sport->port.state->port.tty;
> +
> +	if (sport->rx_bytes) {
> +		tty_insert_flip_string(tty, sport->rx_buf, sport->rx_bytes);
> +		tty_flip_buffer_push(tty);
> +		sport->rx_bytes = 0;
> +	}
> +
> +	if (sport->dma_is_rxing)
> +		start_rx_dma(sport);
> +}
> +
> +static void imx_finish_dma(struct imx_port *sport)
> +{
> +	unsigned long temp;
> +
> +	/* Enable the interrupt when the RXFIFO is not empty. */
> +	temp = readl(sport->port.membase + UCR1);
> +	temp |= UCR1_RRDYEN;
> +	writel(temp, sport->port.membase + UCR1);
> +
> +	sport->dma_is_rxing = false;
> +	if (waitqueue_active(&sport->dma_wait))
> +		wake_up(&sport->dma_wait);
> +}
> +
> +/*
> + * There are three kinds of RX DMA interrupts in the MX6Q:
> + *   [1] the RX DMA buffer is full.
> + *   [2] the Aging timer expires(wait for 8 bytes long)
> + *   [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
> + *
> + * The [2] and [3] are similar, but [3] is better.
> + * [3] can wait for 32 bytes long, so we do not use [2].
> + */
> +static void dma_rx_callback(void *data)
> +{
> +	struct imx_port *sport = data;
> +	struct dma_chan	*chan = sport->dma_chan_rx;
> +	unsigned int count;
> +	struct tty_struct *tty;
> +	struct scatterlist *sgl;
> +	struct dma_tx_state state;
> +	enum dma_status status;
> +
> +	tty = sport->port.state->port.tty;
> +	sgl = &sport->rx_sgl;
> +
> +	/* unmap it first */
> +	dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
> +
> +	/* If we have finish the reading. we will not accept any more data. */
> +	if (tty->closing) {
> +		imx_finish_dma(sport);
> +		return;
> +	}
> +
> +	status = chan->device->device_tx_status(chan,
> +					(dma_cookie_t)NULL, &state);
> +	count = RX_BUF_SIZE - state.residue;
> +	if (count) {
> +		sport->rx_bytes = count;
> +		schedule_work(&sport->tsk_dma_rx);
> +	} else
> +		imx_finish_dma(sport);
> +}
> +
> +static int start_rx_dma(struct imx_port *sport)
> +{
> +	struct scatterlist *sgl = &sport->rx_sgl;
> +	struct dma_chan	*chan = sport->dma_chan_rx;
> +	struct dma_async_tx_descriptor *desc;
> +	int ret;
> +
> +	sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
> +	ret = dma_map_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
> +	if (ret == 0) {
> +		pr_err("DMA mapping error for RX.\n");
> +		return -EINVAL;
> +	}
> +	desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM, 0);
> +	if (!desc) {
> +		pr_err("We cannot prepare for the RX slave dma!\n");
> +		return -EINVAL;
> +	}
> +	desc->callback = dma_rx_callback;
> +	desc->callback_param = sport;
> +
> +	dmaengine_submit(desc);
> +	dma_async_issue_pending(chan);
> +	return 0;
> +}
> +
> +static void imx_uart_dma_exit(struct imx_port *sport)
> +{
> +	if (sport->dma_chan_rx) {
> +		dma_release_channel(sport->dma_chan_rx);
> +		sport->dma_chan_rx = NULL;
> +
> +		kfree(sport->rx_buf);
> +		sport->rx_buf = NULL;
> +	}
> +
> +	if (sport->dma_chan_tx) {
> +		dma_release_channel(sport->dma_chan_tx);
> +		sport->dma_chan_tx = NULL;
> +	}
> +}
> +
> +/* see the "i.MX61 SDMA Scripts User Manual.doc" for the parameters */
> +static int imx_uart_dma_init(struct imx_port *sport)
> +{
> +	struct dma_slave_config slave_config;
> +	dma_cap_mask_t mask;
> +	int ret;
> +
> +	/* prepare for RX : */
> +	dma_cap_zero(mask);
> +	dma_cap_set(DMA_SLAVE, mask);
> +
> +	sport->dma_data.priority = DMA_PRIO_HIGH;
> +	sport->dma_data.dma_request = sport->dma_req_rx;
> +	sport->dma_data.peripheral_type = IMX_DMATYPE_UART;
> +
> +	sport->dma_chan_rx = dma_request_channel(mask, imx_uart_filter, sport);
> +	if (!sport->dma_chan_rx) {
> +		pr_err("cannot get the DMA channel.\n");
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	slave_config.direction = DMA_DEV_TO_MEM;
> +	slave_config.src_addr = sport->port.mapbase + URXD0;
> +	slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +	slave_config.src_maxburst = RXTL; /* fix me */
> +	ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
> +	if (ret) {
> +		pr_err("error in RX dma configuration.\n");
> +		goto err;
> +	}
> +
> +	sport->rx_buf = kzalloc(PAGE_SIZE, GFP_DMA);
> +	if (!sport->rx_buf) {
> +		pr_err("cannot alloc DMA buffer.\n");
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +	sport->rx_bytes = 0;
> +
> +	/* prepare for TX : */
> +	sport->dma_data.dma_request = sport->dma_req_tx;
> +	sport->dma_chan_tx = dma_request_channel(mask, imx_uart_filter, sport);
> +	if (!sport->dma_chan_tx) {
> +		pr_err("cannot get the TX DMA channel!\n");
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	slave_config.direction = DMA_MEM_TO_DEV;
> +	slave_config.dst_addr = sport->port.mapbase + URTX0;
> +	slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
> +	slave_config.dst_maxburst = TXTL; /* fix me */
> +	ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
> +	if (ret) {
> +		pr_err("error in TX dma configuration.");
> +		goto err;
> +	}
> +
> +	return 0;
> +err:
> +	imx_uart_dma_exit(sport);
> +	return ret;
> +}
> +
>  /* half the RX buffer size */
>  #define CTSTL 16
>  
> @@ -756,6 +1079,19 @@ static int imx_startup(struct uart_port *port)
>  		}
>  	}
>  
> +	/* Enable the SDMA for uart. */
> +	if (sport->enable_dma) {
> +		int ret;
> +		ret = imx_uart_dma_init(sport);
> +		if (ret)
> +			goto error_out3;
> +
> +		sport->port.flags |= UPF_LOW_LATENCY;
> +		INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
> +		INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);
> +		init_waitqueue_head(&sport->dma_wait);
> +	}
> +
>  	/*
>  	 * Finally, clear and enable interrupts
>  	 */
> @@ -763,6 +1099,11 @@ static int imx_startup(struct uart_port *port)
>  
>  	temp = readl(sport->port.membase + UCR1);
>  	temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
> +	if (sport->enable_dma) {
> +		temp |= UCR1_RDMAEN | UCR1_TDMAEN;
> +		/* ICD, wait for more than 32 frames, but it still to short. */
> +		temp |= UCR1_ICD_REG(3);
> +	}
>  
>  	if (USE_IRDA(sport)) {
>  		temp |= UCR1_IREN;
> @@ -806,6 +1147,12 @@ static int imx_startup(struct uart_port *port)
>  		writel(temp, sport->port.membase + UCR3);
>  	}
>  
> +	if (sport->enable_dma) {
> +		temp = readl(sport->port.membase + UCR4);
> +		temp |= UCR4_IDDMAEN;
> +		writel(temp, sport->port.membase + UCR4);
> +	}
> +
>  	/*
>  	 * Enable modem status interrupts
>  	 */
> @@ -840,6 +1187,13 @@ static void imx_shutdown(struct uart_port *port)
>  	struct imx_port *sport = (struct imx_port *)port;
>  	unsigned long temp;
>  
> +	if (sport->enable_dma) {
> +		/* We have to wait for the DMA to finish. */
> +		wait_event(sport->dma_wait, !sport->dma_is_rxing);
> +		imx_stop_rx(port);
> +		imx_uart_dma_exit(sport);
> +	}
> +
>  	temp = readl(sport->port.membase + UCR2);
>  	temp &= ~(UCR2_TXEN);
>  	writel(temp, sport->port.membase + UCR2);
> @@ -875,8 +1229,16 @@ static void imx_shutdown(struct uart_port *port)
>  	temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
>  	if (USE_IRDA(sport))
>  		temp &= ~(UCR1_IREN);
> +	if (sport->enable_dma)
> +		temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN);
>  
>  	writel(temp, sport->port.membase + UCR1);
> +
> +	if (sport->enable_dma) {
> +		temp = readl(sport->port.membase + UCR4);
> +		temp &= ~UCR4_IDDMAEN;
> +		writel(temp, sport->port.membase + UCR4);
> +	}
>  }
>  
>  static void
> @@ -1013,6 +1375,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
>  
>  	ufcr = readl(sport->port.membase + UFCR);
>  	ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
> +	/* set the DTE mode */
> +	if (sport->enable_dte)
> +		ufcr |= UFCR_DCEDTE;
>  	writel(ufcr, sport->port.membase + UFCR);
>  
>  	writel(num, sport->port.membase + UBIR);
> @@ -1409,6 +1774,7 @@ static int serial_imx_probe_dt(struct imx_port *sport,
>  	const struct of_device_id *of_id =
>  			of_match_device(imx_uart_dt_ids, &pdev->dev);
>  	int ret;
> +	u32 dma_req[2];
>  
>  	if (!np)
>  		/* no device tree device */
> @@ -1427,6 +1793,18 @@ static int serial_imx_probe_dt(struct imx_port *sport,
>  	if (of_get_property(np, "fsl,irda-mode", NULL))
>  		sport->use_irda = 1;
>  
> +	if (of_get_property(np, "fsl,enable-dma", NULL))
> +		sport->enable_dma = 1;
> +
> +	if (of_get_property(np, "fsl,enable-dte", NULL))
> +		sport->enable_dte = 1;
> +
> +	if (of_property_read_u32_array(np, "fsl,uart-dma-events", dma_req,
> +				ARRAY_SIZE(dma_req)) == 0) {
> +		sport->dma_req_rx = dma_req[0];
> +		sport->dma_req_tx = dma_req[1];
> +	}
> +
>  	sport->devdata = of_id->data;
>  
>  	return 0;
> -- 
> 1.7.0.4
> 
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-arm-kernel mailing list