예제 #1
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;
}
예제 #2
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;
	}
}
예제 #3
0
/*
 * 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;
	}
}