X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fserial%2Fimx.c;h=4c985e6b3784b0b611413c74deba61a98c086997;hb=6f0d618f0e9b8025d1c3531e82d7cc8455e79394;hp=d273134f9e6cc9cac5964996109350c191d0eb06;hpb=1da177e4c3f41524e886b7f1b8a0c1fc7321cac2;p=linux-2.6 diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index d273134f9e..4c985e6b37 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -124,7 +124,7 @@ static void imx_timeout(unsigned long data) /* * interrupts disabled on entry */ -static void imx_stop_tx(struct uart_port *port, unsigned int tty_stop) +static void imx_stop_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN; @@ -165,13 +165,13 @@ static inline void imx_transmit_buffer(struct imx_port *sport) } while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)); if (uart_circ_empty(xmit)) - imx_stop_tx(&sport->port, 0); + imx_stop_tx(&sport->port); } /* * interrupts disabled on entry */ -static void imx_start_tx(struct uart_port *port, unsigned int tty_start) +static void imx_start_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -196,7 +196,7 @@ static irqreturn_t imx_txint(int irq, void *dev_id, struct pt_regs *regs) } if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - imx_stop_tx(&sport->port, 0); + imx_stop_tx(&sport->port); goto out; } @@ -291,13 +291,31 @@ static unsigned int imx_tx_empty(struct uart_port *port) return USR2((u32)sport->port.membase) & USR2_TXDC ? TIOCSER_TEMT : 0; } +/* + * We have a modem side uart, so the meanings of RTS and CTS are inverted. + */ static unsigned int imx_get_mctrl(struct uart_port *port) { - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + struct imx_port *sport = (struct imx_port *)port; + unsigned int tmp = TIOCM_DSR | TIOCM_CAR; + + if (USR1((u32)sport->port.membase) & USR1_RTSS) + tmp |= TIOCM_CTS; + + if (UCR2((u32)sport->port.membase) & UCR2_CTS) + tmp |= TIOCM_RTS; + + return tmp; } static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct imx_port *sport = (struct imx_port *)port; + + if (mctrl & TIOCM_RTS) + UCR2((u32)sport->port.membase) |= UCR2_CTS; + else + UCR2((u32)sport->port.membase) &= ~UCR2_CTS; } /* @@ -321,18 +339,39 @@ static void imx_break_ctl(struct uart_port *port, int break_state) #define TXTL 2 /* reset default */ #define RXTL 1 /* reset default */ +static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) +{ + unsigned int val; + unsigned int ufcr_rfdiv; + + /* set receiver / transmitter trigger level. + * RFDIV is set such way to satisfy requested uartclk value + */ + val = TXTL<<10 | RXTL; + ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk; + + if(!ufcr_rfdiv) + ufcr_rfdiv = 1; + + if(ufcr_rfdiv >= 7) + ufcr_rfdiv = 6; + else + ufcr_rfdiv = 6 - ufcr_rfdiv; + + val |= UFCR_RFDIV & (ufcr_rfdiv << 7); + + UFCR((u32)sport->port.membase) = val; + + return 0; +} + static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; int retval; - unsigned int val; unsigned long flags; - /* set receiver / transmitter trigger level. We assume - * that RFDIV has been set by the arch setup or by the bootloader. - */ - val = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) | TXTL<<10 | RXTL; - UFCR((u32)sport->port.membase) = val; + imx_setup_ufcr(sport, 0); /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs @@ -737,9 +776,12 @@ static void __init imx_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { + if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) { /* ok, the port was enabled */ unsigned int ucr2, ubir,ubmr, uartclk; + unsigned int baud_raw; + unsigned int ucfr_rfdiv; ucr2 = UCR2((u32)sport->port.membase); @@ -758,9 +800,35 @@ imx_console_get_options(struct imx_port *sport, int *baud, ubir = UBIR((u32)sport->port.membase) & 0xffff; ubmr = UBMR((u32)sport->port.membase) & 0xffff; - uartclk = sport->port.uartclk; - *baud = ((uartclk/16) * (ubir + 1)) / (ubmr + 1); + + ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7; + if (ucfr_rfdiv == 6) + ucfr_rfdiv = 7; + else + ucfr_rfdiv = 6 - ucfr_rfdiv; + + uartclk = imx_get_perclk1(); + uartclk /= ucfr_rfdiv; + + { /* + * The next code provides exact computation of + * baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1)) + * without need of float support or long long division, + * which would be required to prevent 32bit arithmetic overflow + */ + unsigned int mul = ubir + 1; + unsigned int div = 16 * (ubmr + 1); + unsigned int rem = uartclk % div; + + baud_raw = (uartclk / div) * mul; + baud_raw += (rem * mul + div / 2) / div; + *baud = (baud_raw + 50) / 100 * 100; + } + + if(*baud != baud_raw) + printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n", + baud_raw, *baud); } } @@ -787,6 +855,8 @@ imx_console_setup(struct console *co, char *options) else imx_console_get_options(sport, &baud, &parity, &bits); + imx_setup_ufcr(sport, 0); + return uart_set_options(&sport->port, co, baud, parity, bits, flow); } @@ -825,7 +895,7 @@ static struct uart_driver imx_reg = { .cons = IMX_CONSOLE, }; -static int serial_imx_suspend(struct device *_dev, u32 state, u32 level) +static int serial_imx_suspend(struct device *_dev, pm_message_t state, u32 level) { struct imx_port *sport = dev_get_drvdata(_dev);