Exemple #1
0
/**
 * 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;
	}
}
Exemple #2
0
/**
 * 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);
}
/*
 * 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;
	}
}