Exemplo n.º 1
0
static inline void check_modem_status(struct uart_port *port)
{
	uint8_t msr;

	msr = siu_read(port, UART_MSR);
	if ((msr & UART_MSR_ANY_DELTA) == 0)
		return;
	if (msr & UART_MSR_DDCD)
		uart_handle_dcd_change(port, msr & UART_MSR_DCD);
	if (msr & UART_MSR_TERI)
		port->icount.rng++;
	if (msr & UART_MSR_DDSR)
		port->icount.dsr++;
	if (msr & UART_MSR_DCTS)
		uart_handle_cts_change(port, msr & UART_MSR_CTS);

	wake_up_interruptible(&port->info->delta_msr_wait);
}
Exemplo n.º 2
0
static void sbd_status_handle(struct sbd_port *sport)
{
	struct uart_port *uport = &sport->port;
	unsigned int delta;

	delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
	delta >>= (uport->line) % 2;

	if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG))
		uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL));

	if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG))
		uport->icount.dsr++;

	if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) <<
		     S_DUART_IN_PIN_CHNG))
		wake_up_interruptible(&uport->state->port.delta_msr_wait);
}
Exemplo n.º 3
0
void btlinux_handle_mctrl(struct uart_btlinux_port *linux_port, UINT8 signals, UINT8 values)
{
	UINT16 status = 0;

	dbg("[USERSPACE <-- KERNEL] -- signals %x, values %x", signals, values);

	if (values & PORT_DTRDSR_ON) {
		info("BTPORT_DTRDSR_ON");
		status |= TIOCM_DSR;
	};
	if (values & PORT_CTSRTS_ON) {
		info("BTPORT_CTSRTS_ON");
		status |= TIOCM_CTS;
	};
	if (values & PORT_RING_ON) {
		info("BTPORT_RING_ON");
		status |= TIOCM_RNG;
	};
	if (values & PORT_DCD_ON) {
		info("BTPORT_DCD_ON");
		status |= TIOCM_CAR;
	};

	if (signals & MODEM_CNTRL_DTRDSR_MASK) {
		dbg("MODEM_CNTRL_DTRDSR_MASK, SET DTR %d", status & TIOCM_DSR);
		linux_port->port.icount.dsr++;
	}

	if (signals & MODEM_CNTRL_CTSRTS_MASK) {
		dbg("MODEM_CNTRL_CTSRTS_MASK, SET CTS %d", status & TIOCM_CTS);
		uart_handle_cts_change(&linux_port->port, status & TIOCM_CTS);
	}

	if (signals & MODEM_CNTRL_RNG_MASK) {
		dbg("MODEM_CNTRL_RNG_MASK, SET DTR %d", status & TIOCM_RNG);
		linux_port->port.icount.rng++;
	}
	if (signals & MODEM_CNTRL_CAR_MASK) {
		dbg("MODEM_CNTRL_CAR_MASK, SET CAR %d", status & TIOCM_CAR);
		uart_handle_dcd_change(&linux_port->port, status & TIOCM_CAR);
	}
}
Exemplo n.º 4
0
static void serial98_modem_status(struct uart_port *port)
{
	int status;

	status = serial98_msr_in(port);

	if ((status & UART_MSR_ANY_DELTA) == 0)
		return;

	if (status & UART_MSR_TERI)
		PORT.icount.rng++;
	if (status & UART_MSR_DDSR)
		PORT.icount.dsr++;
	if (status & UART_MSR_DDCD)
		uart_handle_dcd_change(&PORT, status & UART_MSR_DCD);
	if (status & UART_MSR_DCTS)
		uart_handle_cts_change(&PORT, status & UART_MSR_CTS);

	wake_up_interruptible(&PORT.info->delta_msr_wait);
}
Exemplo n.º 5
0
static void tegra_uart_handle_modem_signal_change(struct uart_port *u)
{
	struct tegra_uart_port *tup = to_tegra_uport(u);
	unsigned long msr;

	msr = tegra_uart_read(tup, UART_MSR);
	if (!(msr & UART_MSR_ANY_DELTA))
		return;

	if (msr & UART_MSR_TERI)
		tup->uport.icount.rng++;
	if (msr & UART_MSR_DDSR)
		tup->uport.icount.dsr++;
	/* We may only get DDCD when HW init and reset */
	if (msr & UART_MSR_DDCD)
		uart_handle_dcd_change(&tup->uport, msr & UART_MSR_DCD);
	/* Will start/stop_tx accordingly */
	if (msr & UART_MSR_DCTS)
		uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
}
Exemplo n.º 6
0
static _INLINE_ void check_modem_status(struct uart_8250_port *up)
{
	int status;

	status = serial_in(up, UART_MSR);

	if ((status & UART_MSR_ANY_DELTA) == 0)
		return;

	if (status & UART_MSR_TERI)
		up->port.icount.rng++;
	if (status & UART_MSR_DDSR)
		up->port.icount.dsr++;
	if (status & UART_MSR_DDCD)
		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
	if (status & UART_MSR_DCTS)
		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);

	wake_up_interruptible(&up->port.info->delta_msr_wait);
}
Exemplo n.º 7
0
/*
 * Handle any change of modem status signal since we were last called.
 */
static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
{
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
	unsigned int status;
	struct uart_info *info = uart->port.info;
	struct tty_struct *tty = info->port.tty;

	status = bfin_serial_get_mctrl(&uart->port);
	uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
	if (!(status & TIOCM_CTS)) {
		tty->hw_stopped = 1;
		uart->cts_timer.data = (unsigned long)(uart);
		uart->cts_timer.function = (void *)bfin_serial_mctrl_check;
		uart->cts_timer.expires = jiffies + CTS_CHECK_JIFFIES;
		add_timer(&(uart->cts_timer));
	} else {
		tty->hw_stopped = 0;
	}
#endif
}
Exemplo n.º 8
0
static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
	struct uart_port *port = &s->p[portno].port;

	do {
		unsigned int iir, msr, rxlen;

		iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
		if (iir & SC16IS7XX_IIR_NO_INT_BIT)
			break;

		iir &= SC16IS7XX_IIR_ID_MASK;

		switch (iir) {
		case SC16IS7XX_IIR_RDI_SRC:
		case SC16IS7XX_IIR_RLSE_SRC:
		case SC16IS7XX_IIR_RTOI_SRC:
		case SC16IS7XX_IIR_XOFFI_SRC:
			rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG);
			if (rxlen)
				sc16is7xx_handle_rx(port, rxlen, iir);
			break;

		case SC16IS7XX_IIR_CTSRTS_SRC:
			msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
			uart_handle_cts_change(port,
					       !!(msr & SC16IS7XX_MSR_CTS_BIT));
			break;
		case SC16IS7XX_IIR_THRI_SRC:
			mutex_lock(&s->mutex);
			sc16is7xx_handle_tx(port);
			mutex_unlock(&s->mutex);
			break;
		default:
			dev_err_ratelimited(port->dev,
					    "Port %i: Unexpected interrupt: %x",
					    port->line, iir);
			break;
		}
	} while (1);
}
Exemplo n.º 9
0
static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
				   struct zilog_channel *channel)
{
	unsigned char status;

	status = readb(&channel->control);
	ZSDELAY();

	writeb(RES_EXT_INT, &channel->control);
	ZSDELAY();
	ZS_WSYNC(channel);

	if (up->curregs[R15] & BRKIE) {
		if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
			if (uart_handle_break(&up->port))
				up->tty_break = Rx_SYS;
			else
				up->tty_break = Rx_BRK;
		}
	}

	if (ZS_WANTS_MODEM_STATUS(up)) {
		if (status & SYNC)
			up->port.icount.dsr++;

		/* The Zilog just gives us an interrupt when DCD/CTS/etc. change.
		 * But it does not tell us which bit has changed, we have to keep
		 * track of this ourselves.
		 */
		if ((status ^ up->prev_status) ^ DCD)
			uart_handle_dcd_change(&up->port,
					       (status & DCD));
		if ((status ^ up->prev_status) ^ CTS)
			uart_handle_cts_change(&up->port,
					       (status & CTS));

		wake_up_interruptible(&up->port.state->port.delta_msr_wait);
	}

	up->prev_status = status;
}
Exemplo n.º 10
0
static void uart00_modem_status(struct uart_port *port)
{
	unsigned int status;

	status = UART_GET_MSR(port);

	if (!(status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | 
			UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK)))
		return;

	if (status & UART_MSR_DDCD_MSK)
		uart_handle_dcd_change(port, status & UART_MSR_DCD_MSK);

	if (status & UART_MSR_DDSR_MSK)
		port->icount.dsr++;

	if (status & UART_MSR_DCTS_MSK)
		uart_handle_cts_change(port, status & UART_MSR_CTS_MSK);

	wake_up_interruptible(&port->info->delta_msr_wait);
}
Exemplo n.º 11
0
/*
 * Interrupt handler
 */
static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	struct uart_port *port = dev_id;
	unsigned int status, pending, pass_counter = 0;

	status = UART_GET_CSR(port);
	pending = status & port->read_status_mask;
	if (pending) {
		do {
			if (pending & AT91_US_RXRDY)
				at91_rx_chars(port, regs);

			/* Clear the relevent break bits */
			if (pending & AT91_US_RXBRK) {
				UART_PUT_CR(port, AT91_US_RSTSTA);
				port->icount.brk++;
				uart_handle_break(port);
			}

			// TODO: All reads to CSR will clear these interrupts!
			if (pending & AT91_US_RIIC) port->icount.rng++;
			if (pending & AT91_US_DSRIC) port->icount.dsr++;
			if (pending & AT91_US_DCDIC)
				uart_handle_dcd_change(port, !(status & AT91_US_DCD));
			if (pending & AT91_US_CTSIC)
				uart_handle_cts_change(port, !(status & AT91_US_CTS));
			if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC))
				wake_up_interruptible(&port->info->delta_msr_wait);

			if (pending & AT91_US_TXRDY)
				at91_tx_chars(port);
			if (pass_counter++ > AT91_ISR_PASS_LIMIT)
				break;

			status = UART_GET_CSR(port);
			pending = status & port->read_status_mask;
		} while (pending);
	}
	return IRQ_HANDLED;
}
Exemplo n.º 12
0
static inline void check_modem_status(struct uart_hsu_port *up)
{
	int status;

	status = serial_in(up, UART_MSR);

	if ((status & UART_MSR_ANY_DELTA) == 0)
		return;

	if (status & UART_MSR_TERI)
		up->port.icount.rng++;
	if (status & UART_MSR_DDSR)
		up->port.icount.dsr++;
	/* We may only get DDCD when HW init and reset */
	if (status & UART_MSR_DDCD)
		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
	/* Will start/stop_tx accordingly */
	if (status & UART_MSR_DCTS)
		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);

	wake_up_interruptible(&up->port.state->port.delta_msr_wait);
}
Exemplo n.º 13
0
static inline void serial_ambarella_check_modem_status(struct uart_port *port)
{
	struct ambarella_uart_port_info		*port_info;
	u32					ms;

	port_info = (struct ambarella_uart_port_info *)(port->private_data);

	if (port_info->get_ms) {
		ms = port_info->get_ms(port->membase);

		if (ms & UART_MS_RI)
			port->icount.rng++;
		if (ms & UART_MS_DSR)
			port->icount.dsr++;
		if (ms & UART_MS_DCTS)
			uart_handle_cts_change(port, (ms & UART_MS_CTS));
		if (ms & UART_MS_DDCD)
			uart_handle_dcd_change(port, (ms & UART_MS_DCD));

		wake_up_interruptible(&port->state->port.delta_msr_wait);
	}
}
Exemplo n.º 14
0
/*
 * Handle any change of modem status signal since we were last called.
 */
static void sa1100_mctrl_check(struct sa1100_port *sport)
{
	unsigned int status, changed;

	status = sport->port.ops->get_mctrl(&sport->port);
	changed = status ^ sport->old_status;

	if (changed == 0)
		return;

	sport->old_status = status;

	if (changed & TIOCM_RI)
		sport->port.icount.rng++;
	if (changed & TIOCM_DSR)
		sport->port.icount.dsr++;
	if (changed & TIOCM_CAR)
		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
	if (changed & TIOCM_CTS)
		uart_handle_cts_change(&sport->port, status & TIOCM_CTS);

	wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
}
Exemplo n.º 15
0
static void pl011_modem_status(struct uart_amba_port *uap)
{
	unsigned int status, delta;

	status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;

	delta = status ^ uap->old_status;
	uap->old_status = status;

	if (!delta)
		return;

	if (delta & UART01x_FR_DCD)
		uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);

	if (delta & UART01x_FR_DSR)
		uap->port.icount.dsr++;

	if (delta & UART01x_FR_CTS)
		uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);

	wake_up_interruptible(&uap->port.info->delta_msr_wait);
}
Exemplo n.º 16
0
static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id)
{
	struct uart_port *port = dev_id;
	unsigned int status;

	
	status = UART_GET_MSR(port);

	if (status & URMS_URDDCD)
		uart_handle_dcd_change(port, status & URMS_URDDCD);

	if (status & URMS_URDDST)
		port->icount.dsr++;

	if (status & URMS_URDCTS)
		uart_handle_cts_change(port, status & URMS_URDCTS);

	if (status & URMS_URTERI)
		port->icount.rng++;

	wake_up_interruptible(&port->state->port.delta_msr_wait);

	return IRQ_HANDLED;
}
Exemplo n.º 17
0
static unsigned int sw_uart_modem_status(struct sw_uart_port *sw_uport)
{
	unsigned int status = serial_in(&sw_uport->port, SW_UART_MSR);

	status |= sw_uport->msr_saved_flags;
	sw_uport->msr_saved_flags = 0;

	if (status & SW_UART_MSR_ANY_DELTA && sw_uport->ier & SW_UART_IER_MSI &&
	    sw_uport->port.state != NULL) {
		if (status & SW_UART_MSR_TERI)
			sw_uport->port.icount.rng++;
		if (status & SW_UART_MSR_DDSR)
			sw_uport->port.icount.dsr++;
		if (status & SW_UART_MSR_DDCD)
			uart_handle_dcd_change(&sw_uport->port, status & SW_UART_MSR_DCD);
		if (!(sw_uport->mcr & SW_UART_MCR_AFE) && status & SW_UART_MSR_DCTS)
			uart_handle_cts_change(&sw_uport->port, status & SW_UART_MSR_CTS);

		wake_up_interruptible(&sw_uport->port.state->port.delta_msr_wait);
	}

	SERIAL_DBG("modem status: %x\n", status);
	return status;
}
Exemplo n.º 18
0
static void lh7a40xuart_modem_status (struct uart_port* port)
{
	unsigned int status = UR (port, UART_R_STATUS);
	unsigned int delta
		= status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;

	BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */

	if (!delta)		/* Only happens if we missed 2 transitions */
		return;

	((struct uart_port_lh7a40x*) port)->statusPrev = status;

	if (delta & DCD)
		uart_handle_dcd_change (port, status & DCD);

	if (delta & DSR)
		++port->icount.dsr;

	if (delta & CTS)
		uart_handle_cts_change (port, status & CTS);

	wake_up_interruptible (&port->info->delta_msr_wait);
}
Exemplo n.º 19
0
static void
serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
			struct ktermios *old)
{
	struct uart_omap_port *up = (struct uart_omap_port *)port;
	unsigned char cval = 0;
	unsigned long flags = 0;
	unsigned int baud, quot;
	unsigned int status;

	switch (termios->c_cflag & CSIZE) {
	case CS5:
		cval = UART_LCR_WLEN5;
		break;
	case CS6:
		cval = UART_LCR_WLEN6;
		break;
	case CS7:
		cval = UART_LCR_WLEN7;
		break;
	default:
	case CS8:
		cval = UART_LCR_WLEN8;
		break;
	}

	if (termios->c_cflag & CSTOPB)
		cval |= UART_LCR_STOP;
	if (termios->c_cflag & PARENB)
		cval |= UART_LCR_PARITY;
	if (!(termios->c_cflag & PARODD))
		cval |= UART_LCR_EPAR;

	/*
	 * Ask the core to calculate the divisor for us.
	 */

	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
	quot = serial_omap_get_divisor(port, baud);

	up->dll = quot & 0xff;
	up->dlh = quot >> 8;
	up->mdr1 = UART_OMAP_MDR1_DISABLE;

	up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
			UART_FCR_ENABLE_FIFO;
	if (up->use_dma)
		up->fcr |= UART_FCR_DMA_SELECT;

	/*
	 * Ok, we're now changing the port state. Do it with
	 * interrupts disabled.
	 */
	serial_omap_port_enable(up);
	spin_lock_irqsave(&up->port.lock, flags);

	/*
	 * Update the per-port timeout.
	 */
	uart_update_timeout(port, termios->c_cflag, baud);

	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
	if (termios->c_iflag & INPCK)
		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
	if (termios->c_iflag & (BRKINT | PARMRK))
		up->port.read_status_mask |= UART_LSR_BI;

	/*
	 * Characters to ignore
	 */
	up->port.ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
	if (termios->c_iflag & IGNBRK) {
		up->port.ignore_status_mask |= UART_LSR_BI;
		/*
		 * If we're ignoring parity and break indicators,
		 * ignore overruns too (for real raw support).
		 */
		if (termios->c_iflag & IGNPAR)
			up->port.ignore_status_mask |= UART_LSR_OE;
	}

	/*
	 * ignore all characters if CREAD is not set
	 */
	if ((termios->c_cflag & CREAD) == 0)
		up->port.ignore_status_mask |= UART_LSR_DR;

	/*
	 * Modem status interrupts
	 */
	up->ier &= ~UART_IER_MSI;
	//if (UART_ENABLE_MS(&up->port, termios->c_cflag))
	if (UART_ENABLE_MS(&up->port, termios->c_cflag)) {
		status = serial_in(up, UART_MSR);
		if (status & UART_MSR_CTS)
			uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
 		up->ier |= UART_IER_MSI;
	}
	serial_out(up, UART_IER, up->ier);
	serial_out(up, UART_LCR, cval);		/* reset DLAB */
	up->lcr = cval;
	up->scr = OMAP_UART_SCR_TX_EMPTY;

	/* FIFOs and DMA Settings */
	/* FCR can be changed only when the
	 * baud clock is not running
	 * DLL_REG and DLH_REG set to 0.
	 */
	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
	serial_out(up, UART_DLL, 0);
	serial_out(up, UART_DLM, 0);
	serial_out(up, UART_LCR, 0);

	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

	up->efr = serial_in(up, UART_EFR);
	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);

	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
	up->mcr = serial_in(up, UART_MCR);
	serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
	/* FIFO ENABLE, DMA MODE */
	serial_out(up, UART_FCR, up->fcr);
	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

	if (up->use_dma) {
		if (up->errata & OMAP4_UART_ERRATA_i659_TX_THR) {
			serial_out(up, UART_MDR3, SET_DMA_TX_THRESHOLD);
			serial_out(up, UART_TX_DMA_THRESHOLD, TX_FIFO_THR_LVL);
		}

		serial_out(up, UART_TI752_TLR, 0);
		up->scr |= (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8);
	}

	serial_out(up, UART_OMAP_SCR, up->scr);
	serial_out(up, UART_EFR, up->efr);
	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
	serial_out(up, UART_MCR, up->mcr);

	/* Protocol, Baud Rate, and Interrupt Settings */
	if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
		omap_uart_mdr1_errataset(up, up->mdr1);
	else
		serial_out(up, UART_OMAP_MDR1, up->mdr1);

	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

	up->efr = serial_in(up, UART_EFR);
	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);

	serial_out(up, UART_LCR, 0);
	serial_out(up, UART_IER, 0);
	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

	serial_out(up, UART_DLL, up->dll);	/* LS of divisor */
	serial_out(up, UART_DLM, up->dlh);	/* MS of divisor */

	serial_out(up, UART_LCR, 0);
	serial_out(up, UART_IER, up->ier);
	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

	serial_out(up, UART_EFR, up->efr);
	serial_out(up, UART_LCR, cval);

	if (baud > 230400 && baud != 3000000)
		up->mdr1 = UART_OMAP_MDR1_13X_MODE;
	else
		up->mdr1 = UART_OMAP_MDR1_16X_MODE;

	if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
		omap_uart_mdr1_errataset(up, up->mdr1);
	else
		serial_out(up, UART_OMAP_MDR1, up->mdr1);

	/* Hardware Flow Control Configuration */

	if (termios->c_cflag & CRTSCTS) {
		serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
		up->mcr = serial_in(up, UART_MCR);
		serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);

		serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
		up->efr = serial_in(up, UART_EFR);
		serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
		serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);

		up->efr |= (UART_EFR_CTS | UART_EFR_RTS);
		serial_out(up, UART_EFR, up->efr); /* Enable AUTORTS and AUTOCTS */
		serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
		up->mcr |= UART_MCR_RTS;
		serial_out(up, UART_MCR, up->mcr);
		serial_out(up, UART_LCR, cval);
	} else {
		serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
		up->efr = serial_in(up, UART_EFR);
		up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
		serial_out(up, UART_EFR, up->efr); /* Disable AUTORTS and AUTOCTS */
		serial_out(up, UART_LCR, cval);
	}

	serial_omap_set_mctrl(&up->port, up->port.mctrl);
	/* Software Flow Control Configuration */
	serial_omap_configure_xonxoff(up, termios);

	/* Now we are ready for RX data: enable rts line */
	if (up->rts_mux_driver_control && up->rts_pullup_in_suspend) {
		omap_rts_mux_write(0, up->port.line);
		up->rts_pullup_in_suspend = 0;
	}

	spin_unlock_irqrestore(&up->port.lock, flags);
	serial_omap_port_disable(up);
	dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
}
Exemplo n.º 20
0
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
{
	unsigned long intr_status;
	unsigned long cts_status;
	unsigned long flag = TTY_NORMAL;
	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
	struct uart_port *port = &sirfport->port;
	struct uart_state *state = port->state;
	struct circ_buf *xmit = &port->state->xmit;
	spin_lock(&port->lock);
	intr_status = rd_regl(port, SIRFUART_INT_STATUS);
	wr_regl(port, SIRFUART_INT_STATUS, intr_status);
	intr_status &= rd_regl(port, SIRFUART_INT_EN);
	if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT))) {
		if (intr_status & SIRFUART_RXD_BREAK) {
			if (uart_handle_break(port))
				goto recv_char;
			uart_insert_char(port, intr_status,
					SIRFUART_RX_OFLOW, 0, TTY_BREAK);
			spin_unlock(&port->lock);
			return IRQ_HANDLED;
		}
		if (intr_status & SIRFUART_RX_OFLOW)
			port->icount.overrun++;
		if (intr_status & SIRFUART_FRM_ERR) {
			port->icount.frame++;
			flag = TTY_FRAME;
		}
		if (intr_status & SIRFUART_PARITY_ERR)
			flag = TTY_PARITY;
		wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
		wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
		wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
		intr_status &= port->read_status_mask;
		uart_insert_char(port, intr_status,
					SIRFUART_RX_OFLOW_INT, 0, flag);
	}
recv_char:
	if (intr_status & SIRFUART_CTS_INT_EN) {
		cts_status = !(rd_regl(port, SIRFUART_AFC_CTRL) &
							SIRFUART_CTS_IN_STATUS);
		if (cts_status != 0) {
			uart_handle_cts_change(port, 1);
		} else {
			uart_handle_cts_change(port, 0);
			wake_up_interruptible(&state->port.delta_msr_wait);
		}
	}
	if (intr_status & SIRFUART_RX_IO_INT_EN)
		sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
	if (intr_status & SIRFUART_TX_INT_EN) {
		if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
			spin_unlock(&port->lock);
			return IRQ_HANDLED;
		} else {
			sirfsoc_uart_pio_tx_chars(sirfport,
					SIRFSOC_UART_IO_TX_REASONABLE_CNT);
			if ((uart_circ_empty(xmit)) &&
				(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
						SIRFUART_FIFOEMPTY_MASK(port)))
				sirfsoc_uart_stop_tx(port);
		}
	}
	spin_unlock(&port->lock);
	return IRQ_HANDLED;
}
Exemplo n.º 21
0
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
{
	unsigned long intr_status;
	unsigned long cts_status;
	unsigned long flag = TTY_NORMAL;
	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
	struct uart_port *port = &sirfport->port;
	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
	struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
	struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
	struct uart_state *state = port->state;
	struct circ_buf *xmit = &port->state->xmit;
	spin_lock(&port->lock);
	intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
	wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
	intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
	if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
		if (intr_status & uint_st->sirfsoc_rxd_brk) {
			port->icount.brk++;
			if (uart_handle_break(port))
				goto recv_char;
		}
		if (intr_status & uint_st->sirfsoc_rx_oflow)
			port->icount.overrun++;
		if (intr_status & uint_st->sirfsoc_frm_err) {
			port->icount.frame++;
			flag = TTY_FRAME;
		}
		if (intr_status & uint_st->sirfsoc_parity_err)
			flag = TTY_PARITY;
		wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
		wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
		wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
		intr_status &= port->read_status_mask;
		uart_insert_char(port, intr_status,
					uint_en->sirfsoc_rx_oflow_en, 0, flag);
	}
recv_char:
	if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
			(intr_status & SIRFUART_CTS_INT_ST(uint_st)) &&
			!sirfport->tx_dma_state) {
		cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
					SIRFUART_AFC_CTS_STATUS;
		if (cts_status != 0)
			cts_status = 0;
		else
			cts_status = 1;
		uart_handle_cts_change(port, cts_status);
		wake_up_interruptible(&state->port.delta_msr_wait);
	}
	if (sirfport->rx_dma_chan) {
		if (intr_status & uint_st->sirfsoc_rx_timeout)
			sirfsoc_uart_handle_rx_tmo(sirfport);
		if (intr_status & uint_st->sirfsoc_rx_done)
			sirfsoc_uart_handle_rx_done(sirfport);
	} else {
		if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
			sirfsoc_uart_pio_rx_chars(port,
					SIRFSOC_UART_IO_RX_MAX_CNT);
	}
	spin_unlock(&port->lock);
	tty_flip_buffer_push(&state->port);
	spin_lock(&port->lock);
	if (intr_status & uint_st->sirfsoc_txfifo_empty) {
		if (sirfport->tx_dma_chan)
			sirfsoc_uart_tx_with_dma(sirfport);
		else {
			if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
				spin_unlock(&port->lock);
				return IRQ_HANDLED;
			} else {
				sirfsoc_uart_pio_tx_chars(sirfport,
					SIRFSOC_UART_IO_TX_REASONABLE_CNT);
				if ((uart_circ_empty(xmit)) &&
				(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
				ufifo_st->ff_empty(port->line)))
					sirfsoc_uart_stop_tx(port);
			}
		}
	}
	spin_unlock(&port->lock);

	return IRQ_HANDLED;
}
Exemplo n.º 22
0
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
{
	unsigned long intr_status;
	unsigned long cts_status;
	unsigned long flag = TTY_NORMAL;
	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
	struct uart_port *port = &sirfport->port;
	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
	struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
	struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
	struct uart_state *state = port->state;
	struct circ_buf *xmit = &port->state->xmit;
	spin_lock(&port->lock);
	intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
	wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
	intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
	if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st,
				sirfport->uart_reg->uart_type)))) {
		if (intr_status & uint_st->sirfsoc_rxd_brk) {
			port->icount.brk++;
			if (uart_handle_break(port))
				goto recv_char;
		}
		if (intr_status & uint_st->sirfsoc_rx_oflow) {
			port->icount.overrun++;
			flag = TTY_OVERRUN;
		}
		if (intr_status & uint_st->sirfsoc_frm_err) {
			port->icount.frame++;
			flag = TTY_FRAME;
		}
		if (intr_status & uint_st->sirfsoc_parity_err) {
			port->icount.parity++;
			flag = TTY_PARITY;
		}
		wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
		wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
		wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
		intr_status &= port->read_status_mask;
		uart_insert_char(port, intr_status,
					uint_en->sirfsoc_rx_oflow_en, 0, flag);
	}
recv_char:
	if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
			(intr_status & SIRFUART_CTS_INT_ST(uint_st)) &&
			!sirfport->tx_dma_state) {
		cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
					SIRFUART_AFC_CTS_STATUS;
		if (cts_status != 0)
			cts_status = 0;
		else
			cts_status = 1;
		uart_handle_cts_change(port, cts_status);
		wake_up_interruptible(&state->port.delta_msr_wait);
	}
	if (!sirfport->rx_dma_chan &&
		(intr_status & SIRFUART_RX_IO_INT_ST(uint_st))) {
		/*
		 * chip will trigger continuous RX_TIMEOUT interrupt
		 * in RXFIFO empty and not trigger if RXFIFO recevice
		 * data in limit time, original method use RX_TIMEOUT
		 * will trigger lots of useless interrupt in RXFIFO
		 * empty.RXFIFO received one byte will trigger RX_DONE
		 * interrupt.use RX_DONE to wait for data received
		 * into RXFIFO, use RX_THD/RX_FULL for lots data receive
		 * and use RX_TIMEOUT for the last left data.
		 */
		if (intr_status & uint_st->sirfsoc_rx_done) {
			if (!sirfport->is_atlas7) {
				wr_regl(port, ureg->sirfsoc_int_en_reg,
					rd_regl(port, ureg->sirfsoc_int_en_reg)
					& ~(uint_en->sirfsoc_rx_done_en));
				wr_regl(port, ureg->sirfsoc_int_en_reg,
				rd_regl(port, ureg->sirfsoc_int_en_reg)
				| (uint_en->sirfsoc_rx_timeout_en));
			} else {
				wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
					uint_en->sirfsoc_rx_done_en);
				wr_regl(port, ureg->sirfsoc_int_en_reg,
					uint_en->sirfsoc_rx_timeout_en);
			}
		} else {
			if (intr_status & uint_st->sirfsoc_rx_timeout) {
				if (!sirfport->is_atlas7) {
					wr_regl(port, ureg->sirfsoc_int_en_reg,
					rd_regl(port, ureg->sirfsoc_int_en_reg)
					& ~(uint_en->sirfsoc_rx_timeout_en));
					wr_regl(port, ureg->sirfsoc_int_en_reg,
					rd_regl(port, ureg->sirfsoc_int_en_reg)
					| (uint_en->sirfsoc_rx_done_en));
				} else {
					wr_regl(port,
						ureg->sirfsoc_int_en_clr_reg,
						uint_en->sirfsoc_rx_timeout_en);
					wr_regl(port, ureg->sirfsoc_int_en_reg,
						uint_en->sirfsoc_rx_done_en);
				}
			}
			sirfsoc_uart_pio_rx_chars(port, port->fifosize);
		}
	}
	spin_unlock(&port->lock);
	tty_flip_buffer_push(&state->port);
	spin_lock(&port->lock);
	if (intr_status & uint_st->sirfsoc_txfifo_empty) {
		if (sirfport->tx_dma_chan)
			sirfsoc_uart_tx_with_dma(sirfport);
		else {
			if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
				spin_unlock(&port->lock);
				return IRQ_HANDLED;
			} else {
				sirfsoc_uart_pio_tx_chars(sirfport,
						port->fifosize);
				if ((uart_circ_empty(xmit)) &&
				(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
				ufifo_st->ff_empty(port)))
					sirfsoc_uart_stop_tx(port);
			}
		}
	}
	spin_unlock(&port->lock);

	return IRQ_HANDLED;
}
Exemplo n.º 23
0
static void h3600_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
{
    struct uart_info *info = dev_id;
    /* Note: should only call this if something has changed */
    uart_handle_cts_change(info, !(GPLR & GPIO_H3600_COM_CTS));
}
Exemplo n.º 24
0
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
	struct tty_struct *tty = NULL;
	unsigned int status, ch, flg;
	static struct timeval anomaly_start = { .tv_sec = 0 };

	status = UART_GET_LSR(uart);
	UART_CLEAR_LSR(uart);

 	ch = UART_GET_CHAR(uart);
 	uart->port.icount.rx++;

#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
	defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
	if (kgdb_connected && kgdboc_port_line == uart->port.line
		&& kgdboc_break_enabled)
		if (ch == 0x3) {/* Ctrl + C */
			kgdb_breakpoint();
			return;
		}

	if (!uart->port.state || !uart->port.state->port.tty)
		return;
#endif
	tty = uart->port.state->port.tty;

	if (ANOMALY_05000363) {
		/* The BF533 (and BF561) family of processors have a nice anomaly
		 * where they continuously generate characters for a "single" break.
		 * We have to basically ignore this flood until the "next" valid
		 * character comes across.  Due to the nature of the flood, it is
		 * not possible to reliably catch bytes that are sent too quickly
		 * after this break.  So application code talking to the Blackfin
		 * which sends a break signal must allow at least 1.5 character
		 * times after the end of the break for things to stabilize.  This
		 * timeout was picked as it must absolutely be larger than 1
		 * character time +/- some percent.  So 1.5 sounds good.  All other
		 * Blackfin families operate properly.  Woo.
		 */
		if (anomaly_start.tv_sec) {
			struct timeval curr;
			suseconds_t usecs;

			if ((~ch & (~ch + 1)) & 0xff)
				goto known_good_char;

			do_gettimeofday(&curr);
			if (curr.tv_sec - anomaly_start.tv_sec > 1)
				goto known_good_char;

			usecs = 0;
			if (curr.tv_sec != anomaly_start.tv_sec)
				usecs += USEC_PER_SEC;
			usecs += curr.tv_usec - anomaly_start.tv_usec;

			if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
				goto known_good_char;

			if (ch)
				anomaly_start.tv_sec = 0;
			else
				anomaly_start = curr;

			return;

 known_good_char:
			status &= ~BI;
			anomaly_start.tv_sec = 0;
		}
	}

	if (status & BI) {
		if (ANOMALY_05000363)
			if (bfin_revid() < 5)
				do_gettimeofday(&anomaly_start);
		uart->port.icount.brk++;
		if (uart_handle_break(&uart->port))
			goto ignore_char;
		status &= ~(PE | FE);
	}
	if (status & PE)
		uart->port.icount.parity++;
	if (status & OE)
		uart->port.icount.overrun++;
	if (status & FE)
		uart->port.icount.frame++;

	status &= uart->port.read_status_mask;

	if (status & BI)
		flg = TTY_BREAK;
	else if (status & PE)
		flg = TTY_PARITY;
	else if (status & FE)
		flg = TTY_FRAME;
	else
		flg = TTY_NORMAL;

	if (uart_handle_sysrq_char(&uart->port, ch))
		goto ignore_char;

	uart_insert_char(&uart->port, status, OE, ch, flg);

 ignore_char:
	tty_flip_buffer_push(tty);
}

static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
{
	struct circ_buf *xmit = &uart->port.state->xmit;

	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
#ifdef CONFIG_BF54x
		/* Clear TFI bit */
		UART_PUT_LSR(uart, TFI);
#endif
		/* Anomaly notes:
		 *  05000215 -	we always clear ETBEI within last UART TX
		 *		interrupt to end a string. It is always set
		 *		when start a new tx.
		 */
		UART_CLEAR_IER(uart, ETBEI);
		return;
	}

	if (uart->port.x_char) {
		UART_PUT_CHAR(uart, uart->port.x_char);
		uart->port.icount.tx++;
		uart->port.x_char = 0;
	}

	while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
		UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
		uart->port.icount.tx++;
	}

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(&uart->port);
}

static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
{
	struct bfin_serial_port *uart = dev_id;

	while (UART_GET_LSR(uart) & DR)
		bfin_serial_rx_chars(uart);

	return IRQ_HANDLED;
}

static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
{
	struct bfin_serial_port *uart = dev_id;

#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
	if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
		uart->scts = 0;
		uart_handle_cts_change(&uart->port, uart->scts);
	}
#endif
	spin_lock(&uart->port.lock);
	if (UART_GET_LSR(uart) & THRE)
		bfin_serial_tx_chars(uart);
	spin_unlock(&uart->port.lock);

	return IRQ_HANDLED;
}
#endif

#ifdef CONFIG_SERIAL_BFIN_DMA
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
{
	struct circ_buf *xmit = &uart->port.state->xmit;

	uart->tx_done = 0;

	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
		uart->tx_count = 0;
		uart->tx_done = 1;
		return;
	}

	if (uart->port.x_char) {
		UART_PUT_CHAR(uart, uart->port.x_char);
		uart->port.icount.tx++;
		uart->port.x_char = 0;
	}

	uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
	if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
		uart->tx_count = UART_XMIT_SIZE - xmit->tail;
	blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
					(unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
	set_dma_config(uart->tx_dma_channel,
		set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
			INTR_ON_BUF,
			DIMENSION_LINEAR,
			DATA_SIZE_8,
			DMA_SYNC_RESTART));
	set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
	set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
	set_dma_x_modify(uart->tx_dma_channel, 1);
	SSYNC();
	enable_dma(uart->tx_dma_channel);

	UART_SET_IER(uart, ETBEI);
}

static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
{
	struct tty_struct *tty = uart->port.state->port.tty;
	int i, flg, status;

	status = UART_GET_LSR(uart);
	UART_CLEAR_LSR(uart);

	uart->port.icount.rx +=
		CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
		UART_XMIT_SIZE);

	if (status & BI) {
		uart->port.icount.brk++;
		if (uart_handle_break(&uart->port))
			goto dma_ignore_char;
		status &= ~(PE | FE);
	}
	if (status & PE)
		uart->port.icount.parity++;
	if (status & OE)
		uart->port.icount.overrun++;
	if (status & FE)
		uart->port.icount.frame++;

	status &= uart->port.read_status_mask;

	if (status & BI)
		flg = TTY_BREAK;
	else if (status & PE)
		flg = TTY_PARITY;
	else if (status & FE)
		flg = TTY_FRAME;
	else
		flg = TTY_NORMAL;

	for (i = uart->rx_dma_buf.tail; ; i++) {
		if (i >= UART_XMIT_SIZE)
			i = 0;
		if (i == uart->rx_dma_buf.head)
			break;
		if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
			uart_insert_char(&uart->port, status, OE,
				uart->rx_dma_buf.buf[i], flg);
	}

 dma_ignore_char:
	tty_flip_buffer_push(tty);
}

void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
	int x_pos, pos;

	dma_disable_irq_nosync(uart->rx_dma_channel);
	spin_lock_bh(&uart->rx_lock);

	/* 2D DMA RX buffer ring is used. Because curr_y_count and
	 * curr_x_count can't be read as an atomic operation,
	 * curr_y_count should be read before curr_x_count. When
	 * curr_x_count is read, curr_y_count may already indicate
	 * next buffer line. But, the position calculated here is
	 * still indicate the old line. The wrong position data may
	 * be smaller than current buffer tail, which cause garbages
	 * are received if it is not prohibit.
	 */
	uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
	x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
	uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
	if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
		uart->rx_dma_nrows = 0;
	x_pos = DMA_RX_XCOUNT - x_pos;
	if (x_pos == DMA_RX_XCOUNT)
		x_pos = 0;

	pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
	/* Ignore receiving data if new position is in the same line of
	 * current buffer tail and small.
	 */
	if (pos > uart->rx_dma_buf.tail ||
		uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
		uart->rx_dma_buf.head = pos;
		bfin_serial_dma_rx_chars(uart);
		uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
	}

	spin_unlock_bh(&uart->rx_lock);
	dma_enable_irq(uart->rx_dma_channel);

	mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
}