Beispiel #1
0
static unsigned int imapx200_serial_getclk(struct uart_port *port,
	struct imapx200_uart_clksrc **clksrc, struct clk **clk,
	unsigned int baud)
{
	struct imapx200_uartcfg *cfg = imapx200_port_to_cfg(port);
	struct imapx200_uart_clksrc *clkp;
	struct baud_calc res[MAX_CLKS];
	struct baud_calc *resptr, *best, *sptr;
	int i;

	clkp = cfg->clocks;
	best = NULL;
	if (cfg->clocks_size < 2)
	{
		if (cfg->clocks_size == 0)
			clkp = &tmp_clksrc;		

		imapx200_serial_calcbaud(res, port, clkp, baud);
		best = res;
		resptr = best + 1;
	}
	else
	{
		resptr = res;

		for (i = 0; i < cfg->clocks_size; i++, clkp++)
		{
			if (imapx200_serial_calcbaud(resptr, port, clkp, baud))
				resptr++;
		}
	}

	/* ok, we now need to select the best clock we found */
	if (!best)
	{
		unsigned int deviation = (1<<30)|((1<<30)-1);
		int calc_deviation;

		for (sptr = res; sptr < resptr; sptr++)
		{
			calc_deviation = baud - sptr->calc;
			if (calc_deviation < 0)
				calc_deviation = -calc_deviation;

			if (calc_deviation < deviation)
			{
				best = sptr;
				deviation = calc_deviation;
			}
		}
	}

	/* store results to pass back */
	*clksrc = best->clksrc;
	*clk = best->src;

	return best->divisor;
}
Beispiel #2
0
static int imapx200_serial_resume(struct platform_device *dev)
{
	struct uart_port *port = imapx200_dev_to_port(&dev->dev);
	struct imapx200_uart_port *ourport = to_ourport(port);

	if (port)
	{
		clk_enable(ourport->clk);
		imapx200_serial_resetport(port, imapx200_port_to_cfg(port));
		clk_disable(ourport->clk);

		uart_resume_port(&imapx200_uart_drv, port);
	}

	return 0;
}
Beispiel #3
0
static int imapx200_serial_resume(struct platform_device *dev)
{
	struct uart_port *port = imapx200_dev_to_port(&dev->dev);
	struct imapx200_uart_port *ourport = to_ourport(port);

	if (port)
	{
		clk_enable(ourport->clk);
		imapx200_serial_resetport(port, imapx200_port_to_cfg(port));
		clk_disable(ourport->clk);

		uart_resume_port(&imapx200_uart_drv, port);
	}

	if(port->irq == IRQ_UART3) {
		printk(KERN_ERR "resume port3: mdelay.\n");
		mdelay(20);
	}

	return 0;
}
Beispiel #4
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);
}