Beispiel #1
0
static int s3c2440_serial_setsource(struct uart_port *port,
				     struct s3c24xx_uart_clksrc *clk)
{
	unsigned long ucon = rd_regl(port, S3C2410_UCON);

	

	ucon &= ~S3C2440_UCON_CLKMASK;

	if (strcmp(clk->name, "uclk") == 0)
		ucon |= S3C2440_UCON_UCLK;
	else if (strcmp(clk->name, "pclk") == 0)
		ucon |= S3C2440_UCON_PCLK;
	else if (strcmp(clk->name, "fclk") == 0)
		ucon |= S3C2440_UCON_FCLK;
	else {
		printk(KERN_ERR "unknown clock source %s\n", clk->name);
		return -EINVAL;
	}

	wr_regl(port, S3C2410_UCON, ucon);
	return 0;
}
static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	/* todo - possibly remove AFC and do manual CTS */

#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_MIDAS)
	unsigned int umcon = 0;
	umcon = rd_regl(port, S3C2410_UMCON);

	if (port->line == CONFIG_BT_S3C_UART) {
		if (mctrl & TIOCM_RTS) {
			umcon |= S3C2410_UMCOM_AFC;
		} else {
			umcon &= ~S3C2410_UMCOM_AFC;
		}

	} else if (port->line == CONFIG_GPS_S3C_UART) {
		umcon |= S3C2410_UMCOM_AFC;
	} else {
		umcon &= ~S3C2410_UMCOM_AFC;
	}

	wr_regl(port, S3C2410_UMCON, umcon);
#endif
}
Beispiel #3
0
static int s5pv210_serial_resetport(struct uart_port *port,
					struct s3c2410_uartcfg *cfg)
{
	unsigned long ucon = rd_regl(port, S3C2410_UCON);

	ucon &= S5PV210_UCON_CLKMASK;
	wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
	wr_regl(port, S3C2410_ULCON, cfg->ulcon);

	/* reset both fifos */
	wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
	wr_regl(port, S3C2410_UFCON, cfg->ufcon);

	wr_regl(port, S3C64XX_UINTM, 0xf);
	wr_regl(port, S3C64XX_UINTP, 0xf);

	/* It is need to delay when reset FIFO register */
	udelay(1);
	return 0;
}
Beispiel #4
0
static int imapx200_serial_resetport(struct uart_port *port, struct imapx200_uartcfg *cfg)
{
	dbg("imapx200_serial_resetport: port=%p (%08lx), cfg=%p\n", port, port->mapbase, cfg);

	wr_regl(port, IMAPX200_LCR,  cfg->lcr);
	wr_regl(port, IMAPX200_MCR,  cfg->mcr);


	/* reset tx and rx fifos */

//	printk(KERN_INFO "cfg->fcr is %d\n",cfg->fcr);
	wr_regl(port, IMAPX200_FCR, (cfg->fcr | IMAPX200_FCR_RFIFOR_RX_FIFO_RESET |
		IMAPX200_FCR_XFIFOR_TX_FIFO_RESET));
	wr_regl(port, IMAPX200_FCR, cfg->fcr);
#if defined(FPGA_TEST)
	wr_regl(port, IMAPX200_CKSR,  IMAPX200_CKSR_CKSEL_UEXTCLK);
#else
	wr_regl(port, IMAPX200_CKSR,  IMAPX200_CKSR_CKSEL_PCLK);
#endif
	return 0;
}
Beispiel #5
0
static void sirfsoc_uart_set_termios(struct uart_port *port,
				       struct ktermios *termios,
				       struct ktermios *old)
{
	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
	unsigned long	config_reg = 0;
	unsigned long	baud_rate;
	unsigned long	set_baud;
	unsigned long	flags;
	unsigned long	ic;
	unsigned int	clk_div_reg = 0;
	unsigned long	txfifo_op_reg, ioclk_rate;
	unsigned long	rx_time_out;
	int		threshold_div;
	u32		data_bit_len, stop_bit_len, len_val;
	unsigned long	sample_div_reg = 0xf;
	ioclk_rate	= port->uartclk;

	switch (termios->c_cflag & CSIZE) {
	default:
	case CS8:
		data_bit_len = 8;
		config_reg |= SIRFUART_DATA_BIT_LEN_8;
		break;
	case CS7:
		data_bit_len = 7;
		config_reg |= SIRFUART_DATA_BIT_LEN_7;
		break;
	case CS6:
		data_bit_len = 6;
		config_reg |= SIRFUART_DATA_BIT_LEN_6;
		break;
	case CS5:
		data_bit_len = 5;
		config_reg |= SIRFUART_DATA_BIT_LEN_5;
		break;
	}
	if (termios->c_cflag & CSTOPB) {
		config_reg |= SIRFUART_STOP_BIT_LEN_2;
		stop_bit_len = 2;
	} else
		stop_bit_len = 1;

	spin_lock_irqsave(&port->lock, flags);
	port->read_status_mask = uint_en->sirfsoc_rx_oflow_en;
	port->ignore_status_mask = 0;
	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
		if (termios->c_iflag & INPCK)
			port->read_status_mask |= uint_en->sirfsoc_frm_err_en |
				uint_en->sirfsoc_parity_err_en;
	} else {
		if (termios->c_iflag & INPCK)
			port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
	}
	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
			port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
		if (termios->c_iflag & IGNPAR)
			port->ignore_status_mask |=
				uint_en->sirfsoc_frm_err_en |
				uint_en->sirfsoc_parity_err_en;
		if (termios->c_cflag & PARENB) {
			if (termios->c_cflag & CMSPAR) {
				if (termios->c_cflag & PARODD)
					config_reg |= SIRFUART_STICK_BIT_MARK;
				else
					config_reg |= SIRFUART_STICK_BIT_SPACE;
			} else if (termios->c_cflag & PARODD) {
				config_reg |= SIRFUART_STICK_BIT_ODD;
			} else {
				config_reg |= SIRFUART_STICK_BIT_EVEN;
			}
		}
	} else {
		if (termios->c_iflag & IGNPAR)
			port->ignore_status_mask |=
				uint_en->sirfsoc_frm_err_en;
		if (termios->c_cflag & PARENB)
			dev_warn(port->dev,
					"USP-UART not support parity err\n");
	}
	if (termios->c_iflag & IGNBRK) {
		port->ignore_status_mask |=
			uint_en->sirfsoc_rxd_brk_en;
		if (termios->c_iflag & IGNPAR)
			port->ignore_status_mask |=
				uint_en->sirfsoc_rx_oflow_en;
	}
	if ((termios->c_cflag & CREAD) == 0)
		port->ignore_status_mask |= SIRFUART_DUMMY_READ;
	/* Hardware Flow Control Settings */
	if (UART_ENABLE_MS(port, termios->c_cflag)) {
		if (!sirfport->ms_enabled)
			sirfsoc_uart_enable_ms(port);
	} else {
		if (sirfport->ms_enabled)
			sirfsoc_uart_disable_ms(port);
	}
	baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
	if (ioclk_rate == 150000000) {
		for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
			if (baud_rate == baudrate_to_regv[ic].baud_rate)
				clk_div_reg = baudrate_to_regv[ic].reg_val;
	}
	set_baud = baud_rate;
	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
		if (unlikely(clk_div_reg == 0))
			clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate,
					ioclk_rate, &set_baud);
		wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg);
	} else {
		clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate,
				ioclk_rate, &sample_div_reg);
		sample_div_reg--;
		set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) /
				(sample_div_reg + 1));
		/* setting usp mode 2 */
		len_val = ((1 << SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET) |
				(1 << SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET));
		len_val |= ((clk_div_reg & SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK)
				<< SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET);
		wr_regl(port, ureg->sirfsoc_mode2, len_val);
	}
	if (tty_termios_baud_rate(termios))
		tty_termios_encode_baud_rate(termios, set_baud, set_baud);
	/* set receive timeout && data bits len */
	rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000);
	rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out);
	txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op);
	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_STOP);
	wr_regl(port, ureg->sirfsoc_tx_fifo_op,
			(txfifo_op_reg & ~SIRFUART_FIFO_START));
	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
		config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
		wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
	} else {
		/*tx frame ctrl*/
		len_val = (data_bit_len - 1) << SIRFSOC_USP_TX_DATA_LEN_OFFSET;
		len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
				SIRFSOC_USP_TX_FRAME_LEN_OFFSET;
		len_val |= ((data_bit_len - 1) <<
				SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET);
		len_val |= (((clk_div_reg & 0xc00) >> 10) <<
				SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET);
		wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val);
		/*rx frame ctrl*/
		len_val = (data_bit_len - 1) << SIRFSOC_USP_RX_DATA_LEN_OFFSET;
		len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
				SIRFSOC_USP_RX_FRAME_LEN_OFFSET;
		len_val |= (data_bit_len - 1) <<
				SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET;
		len_val |= (((clk_div_reg & 0xf000) >> 12) <<
				SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET);
		wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
		/*async param*/
		wr_regl(port, ureg->sirfsoc_async_param_reg,
			(SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
			(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
			SIRFSOC_USP_ASYNC_DIV2_OFFSET);
	}
	if (sirfport->tx_dma_chan)
		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);
	else
		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
	if (sirfport->rx_dma_chan)
		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
	else
		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
	/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
	if (set_baud < 1000000)
		threshold_div = 1;
	else
		threshold_div = 2;
	wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl,
				SIRFUART_FIFO_THD(port) / threshold_div);
	wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl,
				SIRFUART_FIFO_THD(port) / threshold_div);
	txfifo_op_reg |= SIRFUART_FIFO_START;
	wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg);
	uart_update_timeout(port, termios->c_cflag, set_baud);
	sirfsoc_uart_start_rx(port);
	wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN);
	spin_unlock_irqrestore(&port->lock, flags);
}
Beispiel #6
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;
}
Beispiel #7
0
static void s3c24xx_serial_set_termios(struct uart_port *port,
                                       struct ktermios *termios,
                                       struct ktermios *old)
{
    struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
    struct s3c24xx_uart_port *ourport = to_ourport(port);
    struct s3c24xx_uart_clksrc *clksrc = NULL;
    struct clk *clk = NULL;
    unsigned long flags;
    unsigned int baud, quot;
    unsigned int ulcon;
    unsigned int umcon;
    unsigned int udivslot = 0;

    /*
     * We don't support modem control lines.
     */
    termios->c_cflag &= ~(HUPCL | CMSPAR);
    termios->c_cflag |= CLOCAL;

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

    baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);

    if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
        quot = port->custom_divisor;
    else
        quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);

    /* check to see if we need  to change clock source */

    if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
        dbg("selecting clock %p\n", clk);
        s3c24xx_serial_setsource(port, clksrc);

        if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
            clk_disable(ourport->baudclk);
            ourport->baudclk  = NULL;
        }

        clk_enable(clk);

        ourport->clksrc = clksrc;
        ourport->baudclk = clk;
        ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
    }

    if (ourport->info->has_divslot) {
        unsigned int div = ourport->baudclk_rate / baud;

        udivslot = udivslot_table[div & 15];
        dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
    }

    switch (termios->c_cflag & CSIZE) {
    case CS5:
        dbg("config: 5bits/char\n");
        ulcon = S3C2410_LCON_CS5;
        break;
    case CS6:
        dbg("config: 6bits/char\n");
        ulcon = S3C2410_LCON_CS6;
        break;
    case CS7:
        dbg("config: 7bits/char\n");
        ulcon = S3C2410_LCON_CS7;
        break;
    case CS8:
    default:
        dbg("config: 8bits/char\n");
        ulcon = S3C2410_LCON_CS8;
        break;
    }

    /* preserve original lcon IR settings */
    ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);

    if (termios->c_cflag & CSTOPB)
        ulcon |= S3C2410_LCON_STOPB;

    umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;

    if (termios->c_cflag & PARENB) {
        if (termios->c_cflag & PARODD)
            ulcon |= S3C2410_LCON_PODD;
        else
            ulcon |= S3C2410_LCON_PEVEN;
    } else {
        ulcon |= S3C2410_LCON_PNONE;
    }

    spin_lock_irqsave(&port->lock, flags);

    dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
        ulcon, quot, udivslot);

    wr_regl(port, S3C2410_ULCON, ulcon);
    wr_regl(port, S3C2410_UBRDIV, quot);
    wr_regl(port, S3C2410_UMCON, umcon);

    if (ourport->info->has_divslot)
        wr_regl(port, S3C2443_DIVSLOT, udivslot);

    dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
        rd_regl(port, S3C2410_ULCON),
        rd_regl(port, S3C2410_UCON),
        rd_regl(port, S3C2410_UFCON));

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

    /*
     * Which character status flags are we interested in?
     */
    port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
    if (termios->c_iflag & INPCK)
        port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;

    /*
     * Which character status flags should we ignore?
     */
    port->ignore_status_mask = 0;
    if (termios->c_iflag & IGNPAR)
        port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
    if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
        port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;

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

    spin_unlock_irqrestore(&port->lock, flags);
}
Beispiel #8
0
static void startup_uart_controller(struct uart_port *port)
{
	unsigned long temp_regv;
	int temp;
	temp_regv = rd_regl(port, SIRFUART_TX_DMA_IO_CTRL);
	wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, temp_regv | SIRFUART_TX_MODE_IO);
	temp_regv = rd_regl(port, SIRFUART_RX_DMA_IO_CTRL);
	wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, temp_regv | SIRFUART_RX_MODE_IO);
	wr_regl(port, SIRFUART_TX_DMA_IO_LEN, 0);
	wr_regl(port, SIRFUART_RX_DMA_IO_LEN, 0);
	wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_RX_EN | SIRFUART_TX_EN);
	wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_RESET);
	wr_regl(port, SIRFUART_TX_FIFO_OP, 0);
	wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
	wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
	temp = port->line == 1 ? 16 : 64;
	wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp);
	wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp);
}
Beispiel #9
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;
}
Beispiel #10
0
static inline void SELECT_TX_CHANNEL (hrz_dev * dev, u16 tx_channel) {
  wr_regl (dev, TX_CHANNEL_PORT_OFF, tx_channel);
  return;
}
Beispiel #11
0
static inline u32 rd_framer (const hrz_dev * dev, u32 addr) {
  wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr | 0x80000000);
  return rd_regl (dev, MEMORY_PORT_OFF);
}
Beispiel #12
0
static inline void wr_framer (const hrz_dev * dev, u32 addr, u32 data) {
  wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr | 0x80000000);
  wr_regl (dev, MEMORY_PORT_OFF, data);
}
Beispiel #13
0
static inline u32 rd_mem (const hrz_dev * dev, HDW * addr) {
  // wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr);
  wr_regl (dev, MEM_RD_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW));
  return rd_regl (dev, MEMORY_PORT_OFF);
}
Beispiel #14
0
/* Read / Write to a given address in Horizon buffer memory.
   Interrupts must be disabled between the address register and data
   port accesses as these must form an atomic operation. */
static inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) {
  // wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr);
  wr_regl (dev, MEM_WR_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW));
  wr_regl (dev, MEMORY_PORT_OFF, data);
}
Beispiel #15
0
static irqreturn_t
s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
{
	struct s3c24xx_uart_port *ourport = dev_id;
	struct uart_port *port = &ourport->port;
	struct tty_struct *tty = port->info->tty;
	unsigned int ufcon, ch, flag, ufstat, uerstat;
	int max_count = 64;

	while (max_count-- > 0) {
		ufcon = rd_regl(port, S3C2410_UFCON);
		ufstat = rd_regl(port, S3C2410_UFSTAT);

		if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
			break;

		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
			if (tty->low_latency)
				tty_flip_buffer_push(tty);

			/*
			 * If this failed then we will throw away the
			 * bytes but must do so to clear interrupts
			 */
		}

		uerstat = rd_regl(port, S3C2410_UERSTAT);
		ch = rd_regb(port, S3C2410_URXH);

		if (port->flags & UPF_CONS_FLOW) {
			int txe = s3c24xx_serial_txempty_nofifo(port);

			if (rx_enabled(port)) {
				if (!txe) {
					rx_enabled(port) = 0;
					continue;
				}
			} else {
				if (txe) {
					ufcon |= S3C2410_UFCON_RESETRX;
					wr_regl(port, S3C2410_UFCON, ufcon);
					rx_enabled(port) = 1;
					goto out;
				}
				continue;
			}
		}

		/* insert the character into the buffer */

		flag = TTY_NORMAL;
		port->icount.rx++;

		if (uerstat & S3C2410_UERSTAT_ANY) {
			dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
			    ch, uerstat);

			/* check for break */
			if (uerstat & S3C2410_UERSTAT_BREAK) {
				dbg("break!\n");
				port->icount.brk++;
				if (uart_handle_break(port))
				    goto ignore_char;
			}

			if (uerstat & S3C2410_UERSTAT_FRAME)
				port->icount.frame++;
			if (uerstat & S3C2410_UERSTAT_OVERRUN)
				port->icount.overrun++;

			uerstat &= port->read_status_mask;

			if (uerstat & S3C2410_UERSTAT_BREAK)
				flag = TTY_BREAK;
			else if (uerstat & S3C2410_UERSTAT_PARITY)
				flag = TTY_PARITY;
			else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(port, ch, regs))
			goto ignore_char;

		if ((uerstat & port->ignore_status_mask) == 0) {
			tty_insert_flip_char(tty, ch, flag);
		}

		if ((uerstat & S3C2410_UERSTAT_OVERRUN) &&
		    tty->flip.count < TTY_FLIPBUF_SIZE) {
			/*
			 * Overrun is special, since it's reported
			 * immediately, and doesn't affect the current
			 * character.
			 */

			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
		}

	ignore_char:
		continue;
	}
	tty_flip_buffer_push(tty);

 out:
	return IRQ_HANDLED;
}
Beispiel #16
0
static irqreturn_t imapx200_serial_rx_chars(int irq, void *dev_id)
{
	struct imapx200_uart_port *ourport = dev_id;
	struct uart_port *port = &ourport->port;
	struct tty_struct *tty = port->state->port.tty;
	unsigned int ch, flag;
	unsigned int usr, rfl, lsr, fcr;
	int max_count = 64;

	while (max_count-- > 0)
	{
		usr = rd_regl(port, IMAPX200_USR);
		rfl = rd_regl(port, IMAPX200_RFL);
		if (imapx200_serial_rx_fifocnt(ourport, usr, rfl) == 0)
			break;

		lsr = rd_regl(port, IMAPX200_LSR);
		ch = rd_regl(port, IMAPX200_RBR);

		if (port->flags & UPF_CONS_FLOW)
		{
			int txe = imapx200_serial_txempty_nofifo(port);

			if (rx_enabled(port))
			{
				if (!txe)
				{
					rx_enabled(port) = 0;
					continue;
				}
			}
			else
			{
				if (txe)
				{
					fcr |= IMAPX200_FCR_RFIFOR_RX_FIFO_RESET | IMAPX200_FCR_FIFOE_FIFO_ENABLE;
					wr_regl(port, IMAPX200_FCR, fcr);
					rx_enabled(port) = 1;
					goto out;
				}
				continue;
			}
		}

		/* insert the character into the buffer */
		flag = TTY_NORMAL;
		port->icount.rx++;

		if (unlikely(lsr & IMAPX200_LSR_ANY))
		{
			dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, lsr);
			
			/* check for break */
			if (lsr & IMAPX200_LSR_BI_Break_INT)
			{
				dbg("break!\n");
				port->icount.brk++;
				if (uart_handle_break(port))
				    goto ignore_char;
			}

			if (lsr & IMAPX200_LSR_FE_FRAME_ERR)
				port->icount.frame++;
			if (lsr & IMAPX200_LSR_OE_OVERRUN_ERR)
				port->icount.overrun++;

			lsr &= port->read_status_mask;

			if (lsr & IMAPX200_LSR_BI_Break_INT)
				flag = TTY_BREAK;
			else if (lsr & IMAPX200_LSR_PE_PARITY_ERR)
				flag = TTY_PARITY;
			else if (lsr & (IMAPX200_LSR_FE_FRAME_ERR | IMAPX200_LSR_OE_OVERRUN_ERR))
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(port, ch))
			goto ignore_char;

		uart_insert_char(port, lsr, IMAPX200_LSR_OE_OVERRUN_ERR, ch, flag);

 ignore_char:
		continue;
	}
	tty_flip_buffer_push(tty);

 out:
	return IRQ_HANDLED;
}
Beispiel #17
0
static void imapx200_serial_set_termios(struct uart_port *port,
	struct ktermios *termios, struct ktermios *old)
{
	struct imapx200_uartcfg *cfg = imapx200_port_to_cfg(port);
	struct imapx200_uart_port *ourport = to_ourport(port);
	struct imapx200_uart_clksrc *clksrc = NULL;
	struct clk *clk = NULL;
	unsigned long flags;
	unsigned int baud, divisor = 0;
	unsigned int lcr = 0, mcr = 0;

	/*
	 * We don't support modem control lines.
	 */
	termios->c_cflag &= ~(HUPCL | CMSPAR);
	termios->c_cflag |= CLOCAL;

	/*
	 * Ask the core to calculate the divisor for us.
	 */
	baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);

	if ((baud == 38400) && ((port->flags & UPF_SPD_MASK) == UPF_SPD_CUST))
		divisor = port->custom_divisor;
	else
		divisor = imapx200_serial_getclk(port, &clksrc, &clk, baud);

	/* check to see if we need  to change clock source */
	if (ourport->clksrc != clksrc || ourport->baudclk != clk)
	{
		imapx200_serial_setsource(port, clksrc);
	
		if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk))
		{
			clk_disable(ourport->baudclk);
			ourport->baudclk  = NULL;
		}

		clk_enable(clk);

		ourport->clksrc = clksrc;
		ourport->baudclk = clk;
	}

	switch (termios->c_cflag & CSIZE)
	{
		case CS5:
			dbg("config: 5bits/char\n");
			lcr |= IMAPX200_LCR_DLS_5BIT;
			break;
		case CS6:
			dbg("config: 6bits/char\n");
			lcr |= IMAPX200_LCR_DLS_6BIT;
			break;
		case CS7:
			dbg("config: 7bits/char\n");
			lcr |= IMAPX200_LCR_DLS_7BIT;
			break;
		case CS8:
		default:
			dbg("config: 8bits/char\n");
			lcr |= IMAPX200_LCR_DLS_8BIT;
			break;
	}

	/* preserve original lcon IR settings */
	mcr |= (cfg->mcr & IMAPX200_MCR_SIRE_IRDA_ENABLE);

	if (termios->c_cflag & CSTOPB)
		lcr |= IMAPX200_LCR_STOP_1POINT5_2_STOP_BIT;

	if (termios->c_cflag & CRTSCTS) 
		mcr |= IMAPX200_MCR_AFCE_AFC_ENABLE;
	else
		mcr &= ~IMAPX200_MCR_AFCE_AFC_ENABLE;

	if (termios->c_cflag & PARENB)
	{
		lcr |= IMAPX200_LCR_PEN_PARITY_ENABLE;
		if (termios->c_cflag & PARODD)
			lcr &= ~IMAPX200_LCR_EPS_EVEN_PARITY;
		else
			lcr |= IMAPX200_LCR_EPS_EVEN_PARITY;
	}
	else
	{
		lcr &= ~IMAPX200_LCR_PEN_PARITY_ENABLE;
	}

	spin_lock_irqsave(&port->lock, flags);

	dbg("setting lcr to %08x, divisor to %d\n", lcr, divisor);

	wr_regl(port, IMAPX200_LCR, (lcr | IMAPX200_LCR_DLAB_ENABLE));
	wr_regl(port, IMAPX200_DLL, (divisor & 0xff));
	wr_regl(port, IMAPX200_DLH, ((divisor & 0xff00) >> 8));
	wr_regl(port, IMAPX200_LCR, (lcr & ~IMAPX200_LCR_DLAB_ENABLE));
	wr_regl(port, IMAPX200_LCR, lcr);
	wr_regl(port, IMAPX200_MCR, mcr);

	dbg("uart: lcr = 0x%08x, mcr = 0x%08x\n", rd_regl(port, IMAPX200_LCR),
		rd_regl(port, IMAPX200_MCR));

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

	/*
	 * Which character status flags are we interested in?
	 */
	port->read_status_mask = IMAPX200_LSR_OE_MASK;
	if (termios->c_iflag & INPCK)
		port->read_status_mask |= IMAPX200_LSR_FE_MASK | IMAPX200_LSR_PE_MASK;

	/*
	 * Which character status flags should we ignore?
	 */
	port->ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		port->ignore_status_mask |= IMAPX200_LSR_OE_MASK;
	if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
		port->ignore_status_mask |= IMAPX200_LSR_FE_MASK;

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

	spin_unlock_irqrestore(&port->lock, flags);
}
Beispiel #18
0
static enum hrtimer_restart
	sirfsoc_uart_rx_dma_hrtimer_callback(struct hrtimer *hrt)
{
	struct sirfsoc_uart_port *sirfport;
	struct uart_port *port;
	int count, inserted;
	struct dma_tx_state tx_state;
	struct tty_struct *tty;
	struct sirfsoc_register *ureg;
	struct circ_buf *xmit;
	struct sirfsoc_fifo_status *ufifo_st;
	int max_pio_cnt;

	sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt);
	port = &sirfport->port;
	inserted = 0;
	tty = port->state->port.tty;
	ureg = &sirfport->uart_reg->uart_reg;
	xmit = &sirfport->rx_dma_items.xmit;
	ufifo_st = &sirfport->uart_reg->fifo_status;

	dmaengine_tx_status(sirfport->rx_dma_chan,
			sirfport->rx_dma_items.cookie, &tx_state);
	if (SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue !=
		sirfport->rx_last_pos) {
		xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
		sirfport->rx_last_pos = xmit->head;
		sirfport->pio_fetch_cnt = 0;
	}
	count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
			SIRFSOC_RX_DMA_BUF_SIZE);
	while (count > 0) {
		inserted = tty_insert_flip_string(tty->port,
			(const unsigned char *)&xmit->buf[xmit->tail], count);
		if (!inserted)
			goto next_hrt;
		port->icount.rx += inserted;
		xmit->tail = (xmit->tail + inserted) &
				(SIRFSOC_RX_DMA_BUF_SIZE - 1);
		count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
				SIRFSOC_RX_DMA_BUF_SIZE);
		tty_flip_buffer_push(tty->port);
	}
	/*
	 * if RX DMA buffer data have all push into tty buffer, and there is
	 * only little data(less than a dma transfer unit) left in rxfifo,
	 * fetch it out in pio mode and switch back to dma immediately
	 */
	if (!inserted && !count &&
		((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
		SIRFUART_RX_FIFO_MASK) > sirfport->pio_fetch_cnt)) {
		dmaengine_pause(sirfport->rx_dma_chan);
		/* switch to pio mode */
		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
			rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
			SIRFUART_IO_MODE);
		/*
		 * UART controller SWH_DMA_IO register have CLEAR_RX_ADDR_EN
		 * When found changing I/O to DMA mode, it clears
		 * two low bits of read point;
		 * USP have similar FRADDR_CLR_EN bit in USP_RX_DMA_IO_CTRL.
		 * Fetch data out from rxfifo into DMA buffer in PIO mode,
		 * while switch back to DMA mode, the data fetched will override
		 * by DMA, as hardware have a strange behaviour:
		 * after switch back to DMA mode, check rxfifo status it will
		 * be the number PIO fetched, so record the fetched data count
		 * to avoid the repeated fetch
		 */
		max_pio_cnt = 3;
		while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
			ufifo_st->ff_empty(port)) && max_pio_cnt--) {
			xmit->buf[xmit->head] =
				rd_regl(port, ureg->sirfsoc_rx_fifo_data);
			xmit->head = (xmit->head + 1) &
					(SIRFSOC_RX_DMA_BUF_SIZE - 1);
			sirfport->pio_fetch_cnt++;
		}
		/* switch back to dma mode */
		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
			rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
			~SIRFUART_IO_MODE);
		dmaengine_resume(sirfport->rx_dma_chan);
	}
next_hrt:
	hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time));
	return HRTIMER_RESTART;
}
Beispiel #19
0
static void sirfsoc_uart_stop_tx(struct uart_port *port)
{
	unsigned int regv;
	regv = rd_regl(port, SIRFUART_INT_EN);
	wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
}
Beispiel #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 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;
}
Beispiel #21
0
static void sirfsoc_uart_set_termios(struct uart_port *port,
				       struct ktermios *termios,
				       struct ktermios *old)
{
	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
	unsigned long	config_reg = 0;
	unsigned long	baud_rate;
	unsigned long	setted_baud;
	unsigned long	flags;
	unsigned long	ic;
	unsigned int	clk_div_reg = 0;
	unsigned long	temp_reg_val;
	unsigned long	rx_time_out;
	int		threshold_div;
	int		temp;

	switch (termios->c_cflag & CSIZE) {
	default:
	case CS8:
		config_reg |= SIRFUART_DATA_BIT_LEN_8;
		break;
	case CS7:
		config_reg |= SIRFUART_DATA_BIT_LEN_7;
		break;
	case CS6:
		config_reg |= SIRFUART_DATA_BIT_LEN_6;
		break;
	case CS5:
		config_reg |= SIRFUART_DATA_BIT_LEN_5;
		break;
	}
	if (termios->c_cflag & CSTOPB)
		config_reg |= SIRFUART_STOP_BIT_LEN_2;
	baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
	spin_lock_irqsave(&port->lock, flags);
	port->read_status_mask = SIRFUART_RX_OFLOW_INT;
	port->ignore_status_mask = 0;
	/* read flags */
	if (termios->c_iflag & INPCK)
		port->read_status_mask |=
			SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
	if (termios->c_iflag & (BRKINT | PARMRK))
		port->read_status_mask |= SIRFUART_RXD_BREAK_INT;
	/* ignore flags */
	if (termios->c_iflag & IGNPAR)
		port->ignore_status_mask |=
			SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
	if ((termios->c_cflag & CREAD) == 0)
		port->ignore_status_mask |= SIRFUART_DUMMY_READ;
	/* enable parity if PARENB is set*/
	if (termios->c_cflag & PARENB) {
		if (termios->c_cflag & CMSPAR) {
			if (termios->c_cflag & PARODD)
				config_reg |= SIRFUART_STICK_BIT_MARK;
			else
				config_reg |= SIRFUART_STICK_BIT_SPACE;
		} else if (termios->c_cflag & PARODD) {
			config_reg |= SIRFUART_STICK_BIT_ODD;
		} else {
			config_reg |= SIRFUART_STICK_BIT_EVEN;
		}
	}
	/* Hardware Flow Control Settings */
	if (UART_ENABLE_MS(port, termios->c_cflag)) {
		if (!sirfport->ms_enabled)
			sirfsoc_uart_enable_ms(port);
	} else {
		if (sirfport->ms_enabled)
			sirfsoc_uart_disable_ms(port);
	}

	if (port->uartclk == 150000000) {
		/* common rate: fast calculation */
		for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
			if (baud_rate == baudrate_to_regv[ic].baud_rate)
				clk_div_reg = baudrate_to_regv[ic].reg_val;
	}

	setted_baud = baud_rate;
	/* arbitary rate setting */
	if (unlikely(clk_div_reg == 0))
		clk_div_reg = sirfsoc_calc_sample_div(baud_rate, port->uartclk,
								&setted_baud);
	wr_regl(port, SIRFUART_DIVISOR, clk_div_reg);

	if (tty_termios_baud_rate(termios))
		tty_termios_encode_baud_rate(termios, setted_baud, setted_baud);

	/* set receive timeout */
	rx_time_out = SIRFSOC_UART_RX_TIMEOUT(baud_rate, 20000);
	rx_time_out = (rx_time_out > 0xFFFF) ? 0xFFFF : rx_time_out;
	config_reg |= SIRFUART_RECV_TIMEOUT(rx_time_out);
	temp_reg_val = rd_regl(port, SIRFUART_TX_FIFO_OP);
	wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
	wr_regl(port, SIRFUART_TX_FIFO_OP,
				temp_reg_val & ~SIRFUART_TX_FIFO_START);
	wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, SIRFUART_TX_MODE_IO);
	wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, SIRFUART_RX_MODE_IO);
	wr_regl(port, SIRFUART_LINE_CTRL, config_reg);

	/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
	if (baud_rate < 1000000)
		threshold_div = 1;
	else
		threshold_div = 2;
	temp = port->line == 1 ? 16 : 64;
	wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp / threshold_div);
	wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp / threshold_div);
	temp_reg_val |= SIRFUART_TX_FIFO_START;
	wr_regl(port, SIRFUART_TX_FIFO_OP, temp_reg_val);
	uart_update_timeout(port, termios->c_cflag, baud_rate);
	sirfsoc_uart_start_rx(port);
	wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_TX_EN | SIRFUART_RX_EN);
	spin_unlock_irqrestore(&port->lock, flags);
}
Beispiel #22
0
static int sirfsoc_uart_startup(struct uart_port *port)
{
	struct sirfsoc_uart_port *sirfport	= to_sirfport(port);
	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
	unsigned int index			= port->line;
	int ret;
	irq_modify_status(port->irq, IRQ_NOREQUEST, IRQ_NOAUTOEN);
	ret = request_irq(port->irq,
				sirfsoc_uart_isr,
				0,
				SIRFUART_PORT_NAME,
				sirfport);
	if (ret != 0) {
		dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
							index, port->irq);
		goto irq_err;
	}
	/* initial hardware settings */
	wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
		rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
		SIRFUART_IO_MODE);
	wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
		rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
		SIRFUART_IO_MODE);
	wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
		rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
		~SIRFUART_RX_DMA_FLUSH);
	wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
	wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
	wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
	if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
		wr_regl(port, ureg->sirfsoc_mode1,
			SIRFSOC_USP_ENDIAN_CTRL_LSBF |
			SIRFSOC_USP_EN);
	wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
	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_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
	wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
	if (sirfport->rx_dma_chan)
		wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk,
			SIRFUART_RX_FIFO_CHK_SC(port->line, 0x1) |
			SIRFUART_RX_FIFO_CHK_LC(port->line, 0x2) |
			SIRFUART_RX_FIFO_CHK_HC(port->line, 0x4));
	if (sirfport->tx_dma_chan) {
		sirfport->tx_dma_state = TX_DMA_IDLE;
		wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,
				SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) |
				SIRFUART_TX_FIFO_CHK_LC(port->line, 0xe) |
				SIRFUART_TX_FIFO_CHK_HC(port->line, 0x4));
	}
	sirfport->ms_enabled = false;
	if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
		sirfport->hw_flow_ctrl) {
		irq_modify_status(gpio_to_irq(sirfport->cts_gpio),
			IRQ_NOREQUEST, IRQ_NOAUTOEN);
		ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
			sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
			IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
		if (ret != 0) {
			dev_err(port->dev, "UART-USP:request gpio irq fail\n");
			goto init_rx_err;
		}
	}
	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART &&
		sirfport->rx_dma_chan)
		wr_regl(port, ureg->sirfsoc_swh_dma_io,
			SIRFUART_CLEAR_RX_ADDR_EN);
	if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
			sirfport->rx_dma_chan)
		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
			rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
			SIRFSOC_USP_FRADDR_CLR_EN);
	if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) {
		sirfport->is_hrt_enabled = true;
		sirfport->rx_period_time = 20000000;
		sirfport->rx_last_pos = -1;
		sirfport->pio_fetch_cnt = 0;
		sirfport->rx_dma_items.xmit.tail =
			sirfport->rx_dma_items.xmit.head = 0;
		hrtimer_start(&sirfport->hrt,
			ns_to_ktime(sirfport->rx_period_time),
			HRTIMER_MODE_REL);
	}
	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
	if (sirfport->rx_dma_chan)
		sirfsoc_uart_start_next_rx_dma(port);
	else {
		if (!sirfport->is_atlas7)
			wr_regl(port, ureg->sirfsoc_int_en_reg,
				rd_regl(port, ureg->sirfsoc_int_en_reg) |
				SIRFUART_RX_IO_INT_EN(uint_en,
					sirfport->uart_reg->uart_type));
		else
			wr_regl(port, ureg->sirfsoc_int_en_reg,
				SIRFUART_RX_IO_INT_EN(uint_en,
					sirfport->uart_reg->uart_type));
	}
	enable_irq(port->irq);

	return 0;
init_rx_err:
	free_irq(port->irq, sirfport);
irq_err:
	return ret;
}
Beispiel #23
0
static irqreturn_t
s3c24xx_serial_rx_chars(int irq, void *dev_id)
{
    struct s3c24xx_uart_port *ourport = dev_id;
    struct uart_port *port = &ourport->port;
    struct tty_struct *tty = port->state->port.tty;
    unsigned int ufcon, ch, flag, ufstat, uerstat;
    int max_count = 64;

    while (max_count-- > 0) {
        ufcon = rd_regl(port, S3C2410_UFCON);
        ufstat = rd_regl(port, S3C2410_UFSTAT);

        if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
            break;

        uerstat = rd_regl(port, S3C2410_UERSTAT);
        ch = rd_regb(port, S3C2410_URXH);

        if (port->flags & UPF_CONS_FLOW) {
            int txe = s3c24xx_serial_txempty_nofifo(port);

            if (rx_enabled(port)) {
                if (!txe) {
                    rx_enabled(port) = 0;
                    continue;
                }
            } else {
                if (txe) {
                    ufcon |= S3C2410_UFCON_RESETRX;
                    wr_regl(port, S3C2410_UFCON, ufcon);
                    rx_enabled(port) = 1;
                    goto out;
                }
                continue;
            }
        }

        /* insert the character into the buffer */

        flag = TTY_NORMAL;
        port->icount.rx++;

        if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
            dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
                ch, uerstat);

            /* check for break */
            if (uerstat & S3C2410_UERSTAT_BREAK) {
                dbg("break!\n");
                port->icount.brk++;
                if (uart_handle_break(port))
                    goto ignore_char;
            }

            if (uerstat & S3C2410_UERSTAT_FRAME)
                port->icount.frame++;
            if (uerstat & S3C2410_UERSTAT_OVERRUN)
                port->icount.overrun++;

            uerstat &= port->read_status_mask;

            if (uerstat & S3C2410_UERSTAT_BREAK)
                flag = TTY_BREAK;
            else if (uerstat & S3C2410_UERSTAT_PARITY)
                flag = TTY_PARITY;
            else if (uerstat & (S3C2410_UERSTAT_FRAME |
                                S3C2410_UERSTAT_OVERRUN))
                flag = TTY_FRAME;
        }

        if (uart_handle_sysrq_char(port, ch))
            goto ignore_char;

        uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
                         ch, flag);

ignore_char:
        continue;
    }
    tty_flip_buffer_push(tty);

out:
    return IRQ_HANDLED;
}
Beispiel #24
0
static int sirfsoc_uart_startup(struct uart_port *port)
{
	struct sirfsoc_uart_port *sirfport	= to_sirfport(port);
	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
	unsigned int index			= port->line;
	int ret;
	set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
	ret = request_irq(port->irq,
				sirfsoc_uart_isr,
				0,
				SIRFUART_PORT_NAME,
				sirfport);
	if (ret != 0) {
		dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
							index, port->irq);
		goto irq_err;
	}

	/* initial hardware settings */
	wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
		rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
		SIRFUART_IO_MODE);
	wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
		rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
		SIRFUART_IO_MODE);
	wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
	wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
	wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
	if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
		wr_regl(port, ureg->sirfsoc_mode1,
			SIRFSOC_USP_ENDIAN_CTRL_LSBF |
			SIRFSOC_USP_EN);
	wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
	wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
	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_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
	wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
	if (sirfport->rx_dma_chan)
		wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk,
			SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
			SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
			SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
	if (sirfport->tx_dma_chan) {
		sirfport->tx_dma_state = TX_DMA_IDLE;
		wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,
				SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) |
				SIRFUART_TX_FIFO_CHK_LC(port->line, 0xe) |
				SIRFUART_TX_FIFO_CHK_HC(port->line, 0x4));
	}
	sirfport->ms_enabled = false;
	if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
		sirfport->hw_flow_ctrl) {
		set_irq_flags(gpio_to_irq(sirfport->cts_gpio),
			IRQF_VALID | IRQF_NOAUTOEN);
		ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
			sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
			IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
		if (ret != 0) {
			dev_err(port->dev, "UART-USP:request gpio irq fail\n");
			goto init_rx_err;
		}
	}

	enable_irq(port->irq);

	return 0;
init_rx_err:
	free_irq(port->irq, sirfport);
irq_err:
	return ret;
}
Beispiel #25
0
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{
	struct uart_port *port = &ourport->port;
	unsigned int ufcon, ch, flag, ufstat, uerstat;
	unsigned int fifocnt = 0;
	int max_count = port->fifosize;

	while (max_count-- > 0) {
		/*
		 * Receive all characters known to be in FIFO
		 * before reading FIFO level again
		 */
		if (fifocnt == 0) {
			ufstat = rd_regl(port, S3C2410_UFSTAT);
			fifocnt = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
			if (fifocnt == 0)
				break;
		}
		fifocnt--;

		uerstat = rd_regl(port, S3C2410_UERSTAT);
		ch = rd_regb(port, S3C2410_URXH);

		if (port->flags & UPF_CONS_FLOW) {
			int txe = s3c24xx_serial_txempty_nofifo(port);

			if (rx_enabled(port)) {
				if (!txe) {
					rx_enabled(port) = 0;
					continue;
				}
			} else {
				if (txe) {
					ufcon = rd_regl(port, S3C2410_UFCON);
					ufcon |= S3C2410_UFCON_RESETRX;
					wr_regl(port, S3C2410_UFCON, ufcon);
					rx_enabled(port) = 1;
					return;
				}
				continue;
			}
		}

		/* insert the character into the buffer */

		flag = TTY_NORMAL;
		port->icount.rx++;

		if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
			dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
			    ch, uerstat);

			/* check for break */
			if (uerstat & S3C2410_UERSTAT_BREAK) {
				dbg("break!\n");
				port->icount.brk++;
				if (uart_handle_break(port))
					continue; /* Ignore character */
			}

			if (uerstat & S3C2410_UERSTAT_FRAME)
				port->icount.frame++;
			if (uerstat & S3C2410_UERSTAT_OVERRUN)
				port->icount.overrun++;

			uerstat &= port->read_status_mask;

			if (uerstat & S3C2410_UERSTAT_BREAK)
				flag = TTY_BREAK;
			else if (uerstat & S3C2410_UERSTAT_PARITY)
				flag = TTY_PARITY;
			else if (uerstat & (S3C2410_UERSTAT_FRAME |
					    S3C2410_UERSTAT_OVERRUN))
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(port, ch))
			continue; /* Ignore character */

		uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
				 ch, flag);
	}

	tty_flip_buffer_push(&port->state->port);
}
Beispiel #26
0
static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
{
	struct uart_port *port = &sirfport->port;
	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
	struct circ_buf *xmit = &port->state->xmit;
	unsigned long tran_size;
	unsigned long tran_start;
	unsigned long pio_tx_size;

	tran_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
	tran_start = (unsigned long)(xmit->buf + xmit->tail);
	if (uart_circ_empty(xmit) || uart_tx_stopped(port) ||
			!tran_size)
		return;
	if (sirfport->tx_dma_state == TX_DMA_PAUSE) {
		dmaengine_resume(sirfport->tx_dma_chan);
		return;
	}
	if (sirfport->tx_dma_state == TX_DMA_RUNNING)
		return;
	if (!sirfport->is_atlas7)
		wr_regl(port, ureg->sirfsoc_int_en_reg,
				rd_regl(port, ureg->sirfsoc_int_en_reg)&
				~(uint_en->sirfsoc_txfifo_empty_en));
	else
		wr_regl(port, SIRFUART_INT_EN_CLR,
				uint_en->sirfsoc_txfifo_empty_en);
	/*
	 * DMA requires buffer address and buffer length are both aligned with
	 * 4 bytes, so we use PIO for
	 * 1. if address is not aligned with 4bytes, use PIO for the first 1~3
	 * bytes, and move to DMA for the left part aligned with 4bytes
	 * 2. if buffer length is not aligned with 4bytes, use DMA for aligned
	 * part first, move to PIO for the left 1~3 bytes
	 */
	if (tran_size < 4 || BYTES_TO_ALIGN(tran_start)) {
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
			rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)|
			SIRFUART_IO_MODE);
		if (BYTES_TO_ALIGN(tran_start)) {
			pio_tx_size = sirfsoc_uart_pio_tx_chars(sirfport,
				BYTES_TO_ALIGN(tran_start));
			tran_size -= pio_tx_size;
		}
		if (tran_size < 4)
			sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
		if (!sirfport->is_atlas7)
			wr_regl(port, ureg->sirfsoc_int_en_reg,
				rd_regl(port, ureg->sirfsoc_int_en_reg)|
				uint_en->sirfsoc_txfifo_empty_en);
		else
			wr_regl(port, ureg->sirfsoc_int_en_reg,
				uint_en->sirfsoc_txfifo_empty_en);
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
	} else {
		/* tx transfer mode switch into dma mode */
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
			rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)&
			~SIRFUART_IO_MODE);
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
		tran_size &= ~(0x3);

		sirfport->tx_dma_addr = dma_map_single(port->dev,
			xmit->buf + xmit->tail,
			tran_size, DMA_TO_DEVICE);
		sirfport->tx_dma_desc = dmaengine_prep_slave_single(
			sirfport->tx_dma_chan, sirfport->tx_dma_addr,
			tran_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
		if (!sirfport->tx_dma_desc) {
			dev_err(port->dev, "DMA prep slave single fail\n");
			return;
		}
		sirfport->tx_dma_desc->callback =
			sirfsoc_uart_tx_dma_complete_callback;
		sirfport->tx_dma_desc->callback_param = (void *)sirfport;
		sirfport->transfer_size = tran_size;

		dmaengine_submit(sirfport->tx_dma_desc);
		dma_async_issue_pending(sirfport->tx_dma_chan);
		sirfport->tx_dma_state = TX_DMA_RUNNING;
	}
}