コード例 #1
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
/**
 * xuartps_startup - Called when an application opens a xuartps port
 * @port: Handle to the uart port structure
 *
 * Returns 0 on success, negative error otherwise
 **/
static int xuartps_startup(struct uart_port *port)
{
	unsigned int retval = 0, status = 0;

	retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME,
								(void *)port);
	if (retval)
		return retval;

	/* Disable the TX and RX */
	xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
						XUARTPS_CR_OFFSET);

	/* Set the Control Register with TX/RX Enable, TX/RX Reset,
	 * no break chars.
	 */
	xuartps_writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST,
				XUARTPS_CR_OFFSET);

	status = xuartps_readl(XUARTPS_CR_OFFSET);

	/* Clear the RX disable and TX disable bits and then set the TX enable
	 * bit and RX enable bit to enable the transmitter and receiver.
	 */
	xuartps_writel((status & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS))
			| (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN |
			XUARTPS_CR_STOPBRK), XUARTPS_CR_OFFSET);

	/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
	 * no parity.
	 */
	xuartps_writel(XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT
		| XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT,
		 XUARTPS_MR_OFFSET);

	/*
	 * Set the RX FIFO Trigger level to use most of the FIFO, but it
	 * can be tuned with a module parameter
	 */
	xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET);

	/*
	 * Receive Timeout register is enabled but it
	 * can be tuned with a module parameter
	 */
	xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);

	/* Clear out any pending interrupts before enabling them */
	xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET);

	/* Set the Interrupt Registers with desired interrupts */
	xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
		XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
		XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);

	return retval;
}
コード例 #2
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
/**
 * xuartps_resume - Resume after a previous suspend
 * @device: Pointer to the device structure
 *
 * Returns 0
 */
static int xuartps_resume(struct device *device)
{
	struct uart_port *port = dev_get_drvdata(device);
	unsigned long flags = 0;
	u32 ctrl_reg;
	struct tty_struct *tty;
	struct device *tty_dev;
	int may_wake = 0;

	/* Get the tty which could be NULL so don't assume it's valid */
	tty = tty_port_tty_get(&port->state->port);
	if (tty) {
		tty_dev = tty->dev;
		may_wake = device_may_wakeup(tty_dev);
		tty_kref_put(tty);
	}

	if (console_suspend_enabled && !may_wake) {
		struct xuartps *xuartps = port->private_data;

		clk_enable(xuartps->aperclk);
		clk_enable(xuartps->refclk);

		spin_lock_irqsave(&port->lock, flags);

		/* Set TX/RX Reset */
		xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
				(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
				XUARTPS_CR_OFFSET);
		while (xuartps_readl(XUARTPS_CR_OFFSET) &
				(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST))
			cpu_relax();

		/* restore rx timeout value */
		xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);
		/* Enable Tx/Rx */
		ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
		xuartps_writel(
			(ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) |
			(XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
			XUARTPS_CR_OFFSET);

		spin_unlock_irqrestore(&port->lock, flags);
	} else {
		spin_lock_irqsave(&port->lock, flags);
		/* restore original rx trigger level */
		xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET);
		/* enable RX timeout interrupt */
		xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
		spin_unlock_irqrestore(&port->lock, flags);
	}

	return uart_resume_port(&xuartps_uart_driver, port);
}
コード例 #3
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_tx_empty -  Check whether TX is empty
 * @port: Handle to the uart port structure
 *
 * Returns TIOCSER_TEMT on success, 0 otherwise
 **/
static unsigned int xuartps_tx_empty(struct uart_port *port)
{
    unsigned int status;

    status = xuartps_readl(XUARTPS_ISR_OFFSET) & XUARTPS_IXR_TXEMPTY;
    return status ? TIOCSER_TEMT : 0;
}
コード例 #4
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
/**
 * xuartps_set_baud_rate - Calculate and set the baud rate
 * @port: Handle to the uart port structure
 * @baud: Baud rate to set
 * Returns baud rate, requested baud when possible, or actual baud when there
 *	   was too much error, zero if no valid divisors are found.
 */
static unsigned int xuartps_set_baud_rate(struct uart_port *port,
		unsigned int baud)
{
	unsigned int calc_baud;
	u32 cd = 0, bdiv = 0;
	u32 mreg;
	int div8;
	struct xuartps *xuartps = port->private_data;

	calc_baud = xuartps_calc_baud_divs(port->uartclk, baud, &bdiv, &cd,
			&div8);

	/* Write new divisors to hardware */
	mreg = xuartps_readl(XUARTPS_MR_OFFSET);
	if (div8)
		mreg |= XUARTPS_MR_CLKSEL;
	else
		mreg &= ~XUARTPS_MR_CLKSEL;
	xuartps_writel(mreg, XUARTPS_MR_OFFSET);
	xuartps_writel(cd, XUARTPS_BAUDGEN_OFFSET);
	xuartps_writel(bdiv, XUARTPS_BAUDDIV_OFFSET);
	xuartps->baud = baud;

	return calc_baud;
}
コード例 #5
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_console_write - perform write operation
 * @port: Handle to the uart port structure
 * @s: Pointer to character array
 * @count: No of characters
 **/
static void xuartps_console_write(struct console *co, const char *s,
                                  unsigned int count)
{
    struct uart_port *port = &xuartps_port[co->index];
    unsigned long flags;
    unsigned int imr;
    int locked = 1;

    if (oops_in_progress)
        locked = spin_trylock_irqsave(&port->lock, flags);
    else
        spin_lock_irqsave(&port->lock, flags);

    /* save and disable interrupt */
    imr = xuartps_readl(XUARTPS_IMR_OFFSET);
    xuartps_writel(imr, XUARTPS_IDR_OFFSET);

    uart_console_write(port, s, count, xuartps_console_putchar);
    xuartps_console_wait_tx(port);

    /* restore interrupt state, it seems like there may be a h/w bug
     * in that the interrupt enable register should not need to be
     * written based on the data sheet
     */
    xuartps_writel(~imr, XUARTPS_IDR_OFFSET);
    xuartps_writel(imr, XUARTPS_IER_OFFSET);

    if (locked)
        spin_unlock_irqrestore(&port->lock, flags);
}
コード例 #6
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_stop_rx - Stop RX
 * @port: Handle to the uart port structure
 *
 **/
static void xuartps_stop_rx(struct uart_port *port)
{
    unsigned int regval;

    regval = xuartps_readl(XUARTPS_CR_OFFSET);
    regval |= XUARTPS_CR_RX_DIS;
    /* Disable the receiver */
    xuartps_writel(regval, XUARTPS_CR_OFFSET);
}
コード例 #7
0
ファイル: xilinx_uartps.c プロジェクト: Analias/SNOWLeo-SDR-1
/**
 * xuartps_resume - Resume after a previous suspend
 * @device: Pointer to the device structure
 *
 * Returns 0
 */
static int xuartps_resume(struct device *device)
{
	struct uart_port *port = dev_get_drvdata(device);
	unsigned long flags = 0;
	u32 ctrl_reg;
	struct tty_struct *tty;
	struct device *tty_dev;
	int may_wake = 0;

	/* Get the tty which could be NULL so don't assume it's valid */
	tty = tty_port_tty_get(&port->state->port);
	if (tty) {
		tty_dev = tty->dev;
		may_wake = device_may_wakeup(tty_dev);
		tty_kref_put(tty);
	}

	if (console_suspend_enabled && !may_wake) {
		struct xuartps *xuartps = port->private_data;

		clk_enable(xuartps->aperclk);
		clk_enable(xuartps->devclk);

		spin_lock_irqsave(&port->lock, flags);

		/* Set TX/RX Reset */
		xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
				(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
				XUARTPS_CR_OFFSET);

		/* Enable Tx/Rx */
		ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
		xuartps_writel(
			(ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) |
			(XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
			XUARTPS_CR_OFFSET);

		spin_unlock_irqrestore(&port->lock, flags);
	}

	return uart_resume_port(&xuartps_uart_driver, port);
}
コード例 #8
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_start_tx -  Start transmitting bytes
 * @port: Handle to the uart port structure
 *
 **/
static void xuartps_start_tx(struct uart_port *port)
{
    unsigned int status, numbytes = port->fifosize;

    if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))
        return;

    status = xuartps_readl(XUARTPS_CR_OFFSET);
    /* Set the TX enable bit and clear the TX disable bit to enable the
     * transmitter.
     */
    xuartps_writel((status & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN,
                   XUARTPS_CR_OFFSET);

    while (numbytes-- && ((xuartps_readl(XUARTPS_SR_OFFSET)
                           & XUARTPS_SR_TXFULL)) != XUARTPS_SR_TXFULL) {

        /* Break if no more data available in the UART buffer */
        if (uart_circ_empty(&port->state->xmit))
            break;

        /* Get the data from the UART circular buffer and
         * write it to the xuartps's TX_FIFO register.
         */
        xuartps_writel(
            port->state->xmit.buf[port->state->xmit.tail],
            XUARTPS_FIFO_OFFSET);
        port->icount.tx++;

        /* Adjust the tail of the UART buffer and wrap
         * the buffer if it reaches limit.
         */
        port->state->xmit.tail = (port->state->xmit.tail + 1) &
                                 (UART_XMIT_SIZE - 1);
    }

    /* Enable the TX Empty interrupt */
    xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET);

    if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
        uart_write_wakeup(port);
}
コード例 #9
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
static int xuartps_poll_get_char(struct uart_port *port)
{
	u32 imr;
	int c;

	/* Disable all interrupts */
	imr = xuartps_readl(XUARTPS_IMR_OFFSET);
	xuartps_writel(imr, XUARTPS_IDR_OFFSET);

	/* Check if FIFO is empty */
	if (xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY)
		c = NO_POLL_CHAR;
	else /* Read a character */
		c = (unsigned char) xuartps_readl(XUARTPS_FIFO_OFFSET);

	/* Enable interrupts */
	xuartps_writel(imr, XUARTPS_IER_OFFSET);

	return c;
}
コード例 #10
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
/**
 * xuartps_suspend - suspend event
 * @device: Pointer to the device structure
 *
 * Returns 0
 */
static int xuartps_suspend(struct device *device)
{
	struct uart_port *port = dev_get_drvdata(device);
	struct tty_struct *tty;
	struct device *tty_dev;
	int may_wake = 0;

	/* Get the tty which could be NULL so don't assume it's valid */
	tty = tty_port_tty_get(&port->state->port);
	if (tty) {
		tty_dev = tty->dev;
		may_wake = device_may_wakeup(tty_dev);
		tty_kref_put(tty);
	}

	/*
	 * Call the API provided in serial_core.c file which handles
	 * the suspend.
	 */
	uart_suspend_port(&xuartps_uart_driver, port);
	if (console_suspend_enabled && !may_wake) {
		struct xuartps *xuartps = port->private_data;

		clk_disable(xuartps->refclk);
		clk_disable(xuartps->aperclk);
	} else {
		unsigned long flags = 0;

		spin_lock_irqsave(&port->lock, flags);
		/* Empty the receive FIFO 1st before making changes */
		while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY))
			xuartps_readl(XUARTPS_FIFO_OFFSET);
		/* set RX trigger level to 1 */
		xuartps_writel(1, XUARTPS_RXWM_OFFSET);
		/* disable RX timeout interrups */
		xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IDR_OFFSET);
		spin_unlock_irqrestore(&port->lock, flags);
	}

	return 0;
}
コード例 #11
0
ファイル: xilinx_uartps.c プロジェクト: AiWinters/linux
/**
 * xuartps_startup - Called when an application opens a xuartps port
 * @port: Handle to the uart port structure
 *
 * Returns 0 on success, negative error otherwise
 **/
static int xuartps_startup(struct uart_port *port)
{
	unsigned int retval = 0, status = 0;

	retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME,
								(void *)port);
	if (retval)
		return retval;

	/* Disable the TX and RX */
	xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
						XUARTPS_CR_OFFSET);

	/* Set the Control Register with TX/RX Enable, TX/RX Reset,
	 * no break chars.
	 */
	xuartps_writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST,
				XUARTPS_CR_OFFSET);

	status = xuartps_readl(XUARTPS_CR_OFFSET);

	/* Clear the RX disable and TX disable bits and then set the TX enable
	 * bit and RX enable bit to enable the transmitter and receiver.
	 */
	xuartps_writel((status & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS))
			| (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN |
			XUARTPS_CR_STOPBRK), XUARTPS_CR_OFFSET);

	/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
	 * no parity.
	 */
	xuartps_writel(XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT
		| XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT,
		 XUARTPS_MR_OFFSET);

	/* Set the RX FIFO Trigger level to 14 assuming FIFO size as 16 */
	xuartps_writel(14, XUARTPS_RXWM_OFFSET);

	/* Receive Timeout register is enabled with value of 10 */
	xuartps_writel(10, XUARTPS_RXTOUT_OFFSET);


	/* Set the Interrupt Registers with desired interrupts */
	xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
		XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
		XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
	xuartps_writel(~(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
		XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
		XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT), XUARTPS_IDR_OFFSET);

	return retval;
}
コード例 #12
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_shutdown - Called when an application closes a xuartps port
 * @port: Handle to the uart port structure
 *
 **/
static void xuartps_shutdown(struct uart_port *port)
{
    int status;

    /* Disable interrupts */
    status = xuartps_readl(XUARTPS_IMR_OFFSET);
    xuartps_writel(status, XUARTPS_IDR_OFFSET);

    /* Disable the TX and RX */
    xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
                   XUARTPS_CR_OFFSET);
    free_irq(port->irq, port);
}
コード例 #13
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_set_baud_rate - Calculate and set the baud rate
 * @port: Handle to the uart port structure
 * @baud: Baud rate to set
 *
 * Returns baud rate, requested baud when possible, or actual baud when there
 *	was too much error
 **/
static unsigned int xuartps_set_baud_rate(struct uart_port *port,
        unsigned int baud)
{
    unsigned int sel_clk;
    unsigned int calc_baud = 0;
    unsigned int brgr_val, brdiv_val;
    unsigned int bauderror;

    /* Formula to obtain baud rate is
     *	baud_tx/rx rate = sel_clk/CD * (BDIV + 1)
     *	input_clk = (Uart User Defined Clock or Apb Clock)
     *		depends on UCLKEN in MR Reg
     *	sel_clk = input_clk or input_clk/8;
     *		depends on CLKS in MR reg
     *	CD and BDIV depends on values in
     *			baud rate generate register
     *			baud rate clock divisor register
     */
    sel_clk = port->uartclk;
    if (xuartps_readl(XUARTPS_MR_OFFSET) & XUARTPS_MR_CLKSEL)
        sel_clk = sel_clk / 8;

    /* Find the best values for baud generation */
    for (brdiv_val = 4; brdiv_val < 255; brdiv_val++) {

        brgr_val = sel_clk / (baud * (brdiv_val + 1));
        if (brgr_val < 2 || brgr_val > 65535)
            continue;

        calc_baud = sel_clk / (brgr_val * (brdiv_val + 1));

        if (baud > calc_baud)
            bauderror = baud - calc_baud;
        else
            bauderror = calc_baud - baud;

        /* use the values when percent error is acceptable */
        if (((bauderror * 100) / baud) < 3) {
            calc_baud = baud;
            break;
        }
    }

    /* Set the values for the new baud rate */
    xuartps_writel(brgr_val, XUARTPS_BAUDGEN_OFFSET);
    xuartps_writel(brdiv_val, XUARTPS_BAUDDIV_OFFSET);

    return calc_baud;
}
コード例 #14
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
static void xuartps_poll_put_char(struct uart_port *port, unsigned char c)
{
	u32 imr;

	/* Disable all interrupts */
	imr = xuartps_readl(XUARTPS_IMR_OFFSET);
	xuartps_writel(imr, XUARTPS_IDR_OFFSET);

	/* Wait until FIFO is empty */
	while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY))
		cpu_relax();

	/* Write a character */
	xuartps_writel(c, XUARTPS_FIFO_OFFSET);

	/* Wait until FIFO is empty */
	while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY))
		cpu_relax();

	/* Enable interrupts */
	xuartps_writel(imr, XUARTPS_IER_OFFSET);

	return;
}
コード例 #15
0
ファイル: xilinx_uartps.c プロジェクト: Analias/SNOWLeo-SDR-1
/**
 * xuartps_shutdown - Called when an application closes a xuartps port
 * @port: Handle to the uart port structure
 *
 **/
static void xuartps_shutdown(struct uart_port *port)
{
	int status;
	unsigned long flags;

	spin_lock_irqsave(&port->lock, flags);

	/* Disable interrupts */
	status = xuartps_readl(XUARTPS_IMR_OFFSET);
	xuartps_writel(status, XUARTPS_IDR_OFFSET);

	/* Disable the TX and RX */
	xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS,
				 XUARTPS_CR_OFFSET);

	spin_unlock_irqrestore(&port->lock, flags);
	free_irq(port->irq, port);
}
コード例 #16
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_break_ctl - Based on the input ctl we have to start or stop
 *			transmitting char breaks
 * @port: Handle to the uart port structure
 * @ctl: Value based on which start or stop decision is taken
 *
 **/
static void xuartps_break_ctl(struct uart_port *port, int ctl)
{
    unsigned int status;
    unsigned long flags;

    spin_lock_irqsave(&port->lock, flags);

    status = xuartps_readl(XUARTPS_CR_OFFSET);

    if (ctl == -1)
        xuartps_writel(XUARTPS_CR_STARTBRK | status,
                       XUARTPS_CR_OFFSET);
    else {
        if ((status & XUARTPS_CR_STOPBRK) == 0)
            xuartps_writel(XUARTPS_CR_STOPBRK | status,
                           XUARTPS_CR_OFFSET);
    }
    spin_unlock_irqrestore(&port->lock, flags);
}
コード例 #17
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_console_wait_tx - Wait for the TX to be full
 * @port: Handle to the uart port structure
 *
 **/
static void xuartps_console_wait_tx(struct uart_port *port)
{
    while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)
            != XUARTPS_SR_TXEMPTY)
        barrier();
}
コード例 #18
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_set_termios - termios operations, handling data length, parity,
 *				stop bits, flow control, baud rate
 * @port: Handle to the uart port structure
 * @termios: Handle to the input termios structure
 * @old: Values of the previously saved termios structure
 *
 **/
static void xuartps_set_termios(struct uart_port *port,
                                struct ktermios *termios, struct ktermios *old)
{
    unsigned int cval = 0;
    unsigned int baud;
    unsigned long flags;
    unsigned int ctrl_reg, mode_reg;

    spin_lock_irqsave(&port->lock, flags);

    /* Empty the receive FIFO 1st before making changes */
    while ((xuartps_readl(XUARTPS_SR_OFFSET) &
            XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
        xuartps_readl(XUARTPS_FIFO_OFFSET);
    }

    /* Disable the TX and RX to set baud rate */
    xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
                   (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS),
                   XUARTPS_CR_OFFSET);

    /* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */
    baud = uart_get_baud_rate(port, termios, old, 0, 10000000);
    baud = xuartps_set_baud_rate(port, baud);
    if (tty_termios_baud_rate(termios))
        tty_termios_encode_baud_rate(termios, baud, baud);

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

    /* Set TX/RX Reset */
    xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
                   (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
                   XUARTPS_CR_OFFSET);

    ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);

    /* Clear the RX disable and TX disable bits and then set the TX enable
     * bit and RX enable bit to enable the transmitter and receiver.
     */
    xuartps_writel(
        (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS))
        | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
        XUARTPS_CR_OFFSET);

    xuartps_writel(10, XUARTPS_RXTOUT_OFFSET);

    port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG |
                             XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT;
    port->ignore_status_mask = 0;

    if (termios->c_iflag & INPCK)
        port->read_status_mask |= XUARTPS_IXR_PARITY |
                                  XUARTPS_IXR_FRAMING;

    if (termios->c_iflag & IGNPAR)
        port->ignore_status_mask |= XUARTPS_IXR_PARITY |
                                    XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN;

    /* ignore all characters if CREAD is not set */
    if ((termios->c_cflag & CREAD) == 0)
        port->ignore_status_mask |= XUARTPS_IXR_RXTRIG |
                                    XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY |
                                    XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN;

    mode_reg = xuartps_readl(XUARTPS_MR_OFFSET);

    /* Handling Data Size */
    switch (termios->c_cflag & CSIZE) {
    case CS6:
        cval |= XUARTPS_MR_CHARLEN_6_BIT;
        break;
    case CS7:
        cval |= XUARTPS_MR_CHARLEN_7_BIT;
        break;
    default:
    case CS8:
        cval |= XUARTPS_MR_CHARLEN_8_BIT;
        termios->c_cflag &= ~CSIZE;
        termios->c_cflag |= CS8;
        break;
    }

    /* Handling Parity and Stop Bits length */
    if (termios->c_cflag & CSTOPB)
        cval |= XUARTPS_MR_STOPMODE_2_BIT; /* 2 STOP bits */
    else
        cval |= XUARTPS_MR_STOPMODE_1_BIT; /* 1 STOP bit */

    if (termios->c_cflag & PARENB) {
        /* Mark or Space parity */
        if (termios->c_cflag & CMSPAR) {
            if (termios->c_cflag & PARODD)
                cval |= XUARTPS_MR_PARITY_MARK;
            else
                cval |= XUARTPS_MR_PARITY_SPACE;
        } else if (termios->c_cflag & PARODD)
            cval |= XUARTPS_MR_PARITY_ODD;
        else
            cval |= XUARTPS_MR_PARITY_EVEN;
    } else
        cval |= XUARTPS_MR_PARITY_NONE;
    xuartps_writel(cval , XUARTPS_MR_OFFSET);

    spin_unlock_irqrestore(&port->lock, flags);
}
コード例 #19
0
ファイル: xilinx_uartps.c プロジェクト: Niisp/MT6795.kernel
/**
 * xuartps_isr - Interrupt handler
 * @irq: Irq number
 * @dev_id: Id of the port
 *
 * Returns IRQHANDLED
 **/
static irqreturn_t xuartps_isr(int irq, void *dev_id)
{
    struct uart_port *port = (struct uart_port *)dev_id;
    unsigned long flags;
    unsigned int isrstatus, numbytes;
    unsigned int data;
    char status = TTY_NORMAL;

    spin_lock_irqsave(&port->lock, flags);

    /* Read the interrupt status register to determine which
     * interrupt(s) is/are active.
     */
    isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET);

    /* drop byte with parity error if IGNPAR specified */
    if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY)
        isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT);

    isrstatus &= port->read_status_mask;
    isrstatus &= ~port->ignore_status_mask;

    if ((isrstatus & XUARTPS_IXR_TOUT) ||
            (isrstatus & XUARTPS_IXR_RXTRIG)) {
        /* Receive Timeout Interrupt */
        while ((xuartps_readl(XUARTPS_SR_OFFSET) &
                XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
            data = xuartps_readl(XUARTPS_FIFO_OFFSET);
            port->icount.rx++;

            if (isrstatus & XUARTPS_IXR_PARITY) {
                port->icount.parity++;
                status = TTY_PARITY;
            } else if (isrstatus & XUARTPS_IXR_FRAMING) {
                port->icount.frame++;
                status = TTY_FRAME;
            } else if (isrstatus & XUARTPS_IXR_OVERRUN)
                port->icount.overrun++;

            uart_insert_char(port, isrstatus, XUARTPS_IXR_OVERRUN,
                             data, status);
        }
        spin_unlock(&port->lock);
        tty_flip_buffer_push(&port->state->port);
        spin_lock(&port->lock);
    }

    /* Dispatch an appropriate handler */
    if ((isrstatus & XUARTPS_IXR_TXEMPTY) == XUARTPS_IXR_TXEMPTY) {
        if (uart_circ_empty(&port->state->xmit)) {
            xuartps_writel(XUARTPS_IXR_TXEMPTY,
                           XUARTPS_IDR_OFFSET);
        } else {
            numbytes = port->fifosize;
            /* Break if no more data available in the UART buffer */
            while (numbytes--) {
                if (uart_circ_empty(&port->state->xmit))
                    break;
                /* Get the data from the UART circular buffer
                 * and write it to the xuartps's TX_FIFO
                 * register.
                 */
                xuartps_writel(
                    port->state->xmit.buf[port->state->xmit.
                                          tail], XUARTPS_FIFO_OFFSET);

                port->icount.tx++;

                /* Adjust the tail of the UART buffer and wrap
                 * the buffer if it reaches limit.
                 */
                port->state->xmit.tail =
                    (port->state->xmit.tail + 1) & \
                    (UART_XMIT_SIZE - 1);
            }

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

    xuartps_writel(isrstatus, XUARTPS_ISR_OFFSET);

    /* be sure to release the lock and tty before leaving */
    spin_unlock_irqrestore(&port->lock, flags);

    return IRQ_HANDLED;
}
コード例 #20
0
ファイル: xilinx_uartps.c プロジェクト: Analias/SNOWLeo-SDR-1
/*
 * no clue yet how to implement this. i think we need access to the port
 * structure in this function to do the required changes. but i don't know how
 * to get it in here.
 *
 * Think I got it. port must have a notifier_block* member from where we then
 * can get to the outer port structure with a container_of() call.
 *
 * Not sure when to stop UART. probably it's enough to stop, reconfigure, start
 * in POST_RATE_CHANGE
 */
static int xuartps_clk_notifier_cb(struct notifier_block *nb,
		unsigned long event, void *data)
{
	struct clk_notifier_data *ndata = data;
	struct uart_port *port;
	struct xuartps *xuartps = to_xuartps(nb);

	port = xuartps->port;

	switch (event) {
	case PRE_RATE_CHANGE:
	{
		u32 bdiv;
		u32 cd;
		int div8;

		/* Find out if current baud-rate can be achieved with new clock
		 * frequency. */
		if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud,
					&bdiv, &cd, &div8))
			return NOTIFY_BAD;
		return NOTIFY_OK;
	}
	case POST_RATE_CHANGE:
		/* Set clk dividers to generate correct baud with new clock
		 * frequency. */
	{
		u32 ctrl_reg;
		unsigned long flags = 0;

		spin_lock_irqsave(&xuartps->port->lock, flags);

		port->uartclk = ndata->new_rate;
		/* Empty the receive FIFO 1st before making changes */
		while ((xuartps_readl(XUARTPS_SR_OFFSET) &
			 XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY)
			xuartps_readl(XUARTPS_FIFO_OFFSET);

		/* Disable the TX and RX to set baud rate */
		xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
				(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS),
				XUARTPS_CR_OFFSET);

		xuartps->baud = xuartps_set_baud_rate(xuartps->port,
				xuartps->baud);

		/* Set TX/RX Reset */
		xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
				(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
				XUARTPS_CR_OFFSET);

		/*
		 * Clear the RX disable and TX disable bits and then set the TX
		 * enable bit and RX enable bit to enable the transmitter and
		 * receiver.
		 */
		ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
		xuartps_writel(
			(ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) |
			(XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
			XUARTPS_CR_OFFSET);

		spin_unlock_irqrestore(&xuartps->port->lock, flags);
		return NOTIFY_OK;
	}
	case ABORT_RATE_CHANGE:
		return NOTIFY_OK;
	default:
		return NOTIFY_DONE;
	}
}
コード例 #21
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
/**
 * xuartps_isr - Interrupt handler
 * @irq: Irq number
 * @dev_id: Id of the port
 *
 * Returns IRQHANDLED
 **/
static irqreturn_t xuartps_isr(int irq, void *dev_id)
{
	struct uart_port *port = (struct uart_port *)dev_id;
	unsigned long flags;
	unsigned int isrstatus, numbytes;
	unsigned int data;
	char status = TTY_NORMAL;

	spin_lock_irqsave(&port->lock, flags);

	/* Read the interrupt status register to determine which
	 * interrupt(s) is/are active.
	 */
	isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET);

	/*
	 * There is no hardware break detection, so we interpret framing
	 * error with all-zeros data as a break sequence. Most of the time,
	 * there's another non-zero byte at the end of the sequence.
	 */

	if (isrstatus & XUARTPS_IXR_FRAMING) {
		while (!(xuartps_readl(XUARTPS_SR_OFFSET) &
					XUARTPS_SR_RXEMPTY)) {
			if (!xuartps_readl(XUARTPS_FIFO_OFFSET)) {
				port->read_status_mask |= XUARTPS_IXR_BRK;
				isrstatus &= ~XUARTPS_IXR_FRAMING;
			}
		}
		xuartps_writel(XUARTPS_IXR_FRAMING, XUARTPS_ISR_OFFSET);
	}

	/* drop byte with parity error if IGNPAR specified */
	if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY)
		isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT);

	isrstatus &= port->read_status_mask;
	isrstatus &= ~port->ignore_status_mask;

	if ((isrstatus & XUARTPS_IXR_TOUT) ||
		(isrstatus & XUARTPS_IXR_RXTRIG)) {
		/* Receive Timeout Interrupt */
		while ((xuartps_readl(XUARTPS_SR_OFFSET) &
			XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
			data = xuartps_readl(XUARTPS_FIFO_OFFSET);

			/* Non-NULL byte after BREAK is garbage (99%) */
			if (data && (port->read_status_mask &
						XUARTPS_IXR_BRK)) {
				port->read_status_mask &= ~XUARTPS_IXR_BRK;
				port->icount.brk++;
				if (uart_handle_break(port))
					continue;
			}

#ifdef SUPPORT_SYSRQ
			/*
			 * uart_handle_sysrq_char() doesn't work if
			 * spinlocked, for some reason
			 */
			 if (port->sysrq) {
				spin_unlock(&port->lock);
				if (uart_handle_sysrq_char(port,
							(unsigned char)data)) {
					spin_lock(&port->lock);
					continue;
				}
				spin_lock(&port->lock);
			}
#endif

			port->icount.rx++;

			if (isrstatus & XUARTPS_IXR_PARITY) {
				port->icount.parity++;
				status = TTY_PARITY;
			} else if (isrstatus & XUARTPS_IXR_FRAMING) {
				port->icount.frame++;
				status = TTY_FRAME;
			} else if (isrstatus & XUARTPS_IXR_OVERRUN)
				port->icount.overrun++;

			uart_insert_char(port, isrstatus, XUARTPS_IXR_OVERRUN,
					data, status);
		}
		spin_unlock(&port->lock);
		tty_flip_buffer_push(&port->state->port);
		spin_lock(&port->lock);
	}

	/* Dispatch an appropriate handler */
	if ((isrstatus & XUARTPS_IXR_TXEMPTY) == XUARTPS_IXR_TXEMPTY) {
		if (uart_circ_empty(&port->state->xmit)) {
			xuartps_writel(XUARTPS_IXR_TXEMPTY,
						XUARTPS_IDR_OFFSET);
		} else {
			numbytes = port->fifosize;
			/* Break if no more data available in the UART buffer */
			while (numbytes--) {
				if (uart_circ_empty(&port->state->xmit))
					break;
				/* Get the data from the UART circular buffer
				 * and write it to the xuartps's TX_FIFO
				 * register.
				 */
				xuartps_writel(
					port->state->xmit.buf[port->state->xmit.
					tail], XUARTPS_FIFO_OFFSET);

				port->icount.tx++;

				/* Adjust the tail of the UART buffer and wrap
				 * the buffer if it reaches limit.
				 */
				port->state->xmit.tail =
					(port->state->xmit.tail + 1) & \
						(UART_XMIT_SIZE - 1);
			}

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

	xuartps_writel(isrstatus, XUARTPS_ISR_OFFSET);

	/* be sure to release the lock and tty before leaving */
	spin_unlock_irqrestore(&port->lock, flags);

	return IRQ_HANDLED;
}
コード例 #22
0
ファイル: xilinx_uartps.c プロジェクト: 7799/linux
/**
 * xuartps_clk_notitifer_cb - Clock notifier callback
 * @nb:		Notifier block
 * @event:	Notify event
 * @data:	Notifier data
 * Returns NOTIFY_OK on success, NOTIFY_BAD on error.
 */
static int xuartps_clk_notifier_cb(struct notifier_block *nb,
		unsigned long event, void *data)
{
	u32 ctrl_reg;
	struct uart_port *port;
	int locked = 0;
	struct clk_notifier_data *ndata = data;
	unsigned long flags = 0;
	struct xuartps *xuartps = to_xuartps(nb);

	port = xuartps->port;
	if (port->suspended)
		return NOTIFY_OK;

	switch (event) {
	case PRE_RATE_CHANGE:
	{
		u32 bdiv;
		u32 cd;
		int div8;

		/*
		 * Find out if current baud-rate can be achieved with new clock
		 * frequency.
		 */
		if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud,
					&bdiv, &cd, &div8))
			return NOTIFY_BAD;

		spin_lock_irqsave(&xuartps->port->lock, flags);

		/* Disable the TX and RX to set baud rate */
		xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
				(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS),
				XUARTPS_CR_OFFSET);

		spin_unlock_irqrestore(&xuartps->port->lock, flags);

		return NOTIFY_OK;
	}
	case POST_RATE_CHANGE:
		/*
		 * Set clk dividers to generate correct baud with new clock
		 * frequency.
		 */

		spin_lock_irqsave(&xuartps->port->lock, flags);

		locked = 1;
		port->uartclk = ndata->new_rate;

		xuartps->baud = xuartps_set_baud_rate(xuartps->port,
				xuartps->baud);
		/* fall through */
	case ABORT_RATE_CHANGE:
		if (!locked)
			spin_lock_irqsave(&xuartps->port->lock, flags);

		/* Set TX/RX Reset */
		xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
				(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
				XUARTPS_CR_OFFSET);

		while (xuartps_readl(XUARTPS_CR_OFFSET) &
				(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST))
			cpu_relax();

		/*
		 * Clear the RX disable and TX disable bits and then set the TX
		 * enable bit and RX enable bit to enable the transmitter and
		 * receiver.
		 */
		xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);
		ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
		xuartps_writel(
			(ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) |
			(XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
			XUARTPS_CR_OFFSET);

		spin_unlock_irqrestore(&xuartps->port->lock, flags);

		return NOTIFY_OK;
	default:
		return NOTIFY_DONE;
	}
}