From 8c8fdbc9bd9718b21146065de61c0cafdff11ecb Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 1 Apr 2009 12:40:15 +0200 Subject: [ARM] Remove arch-imx from build system arch-imx is superseeded by the MXC architecture support. This patch removes arch-imx from the build system. Signed-off-by: Sascha Hauer --- drivers/serial/imx.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 9f460b1..3f5d5a2 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -66,7 +66,7 @@ #define ONEMS 0xb0 /* One Millisecond register */ #define UTS 0xb4 /* UART Test Register */ #endif -#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) +#ifdef CONFIG_ARCH_MX1 #define BIPR1 0xb0 /* Incremental Preset Register 1 */ #define BIPR2 0xb4 /* Incremental Preset Register 2 */ #define BIPR3 0xb8 /* Incremental Preset Register 3 */ @@ -96,7 +96,7 @@ #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ #define UCR1_SNDBRK (1<<4) /* Send break */ #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) +#ifdef CONFIG_ARCH_MX1 #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ #endif #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2 @@ -127,7 +127,7 @@ #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#ifdef CONFIG_ARCH_IMX +#ifdef CONFIG_ARCH_MX1 #define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ #define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ #endif @@ -180,13 +180,6 @@ #define UTS_SOFTRST (1<<0) /* Software reset */ /* We've been assigned a range on the "Low-density serial ports" major */ -#ifdef CONFIG_ARCH_IMX -#define SERIAL_IMX_MAJOR 204 -#define MINOR_START 41 -#define DEV_NAME "ttySMX" -#define MAX_INTERNAL_IRQ IMX_IRQS -#endif - #ifdef CONFIG_ARCH_MXC #define SERIAL_IMX_MAJOR 207 #define MINOR_START 16 -- cgit v1.1 From 0003b795c310da83501fcf0329f6be7a0984647d Mon Sep 17 00:00:00 2001 From: Eric Lammerts Date: Tue, 19 May 2009 20:53:20 -0400 Subject: fix oops when using console=ttymxcN with N > 0 Signed-off-by: Eric Lammerts Signed-off-by: Sascha Hauer --- drivers/serial/imx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 3f5d5a2..738c8a5 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1024,6 +1024,8 @@ imx_console_setup(struct console *co, char *options) if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) co->index = 0; sport = imx_ports[co->index]; + if(sport == NULL) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); -- cgit v1.1 From e76afc4e7816a0a5300073098cdac93a994eb5ca Mon Sep 17 00:00:00 2001 From: Eric Lammerts Date: Tue, 19 May 2009 20:53:20 -0400 Subject: fix oops when using console=ttymxcN with N > 0 Signed-off-by: Eric Lammerts Signed-off-by: Sascha Hauer --- drivers/serial/imx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 9f460b1..5f0be40 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1031,6 +1031,8 @@ imx_console_setup(struct console *co, char *options) if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) co->index = 0; sport = imx_ports[co->index]; + if(sport == NULL) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); -- cgit v1.1 From d3810cd4d7064b109574374f73c41b11b481dbf2 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Thu, 11 Jun 2009 14:35:01 +0100 Subject: imx: serial: fix whitespaces (no changes in functionality) Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5f0be40..76c8fa1 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -302,8 +302,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) /* send xmit->buf[xmit->tail] * out the port here */ writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); - xmit->tail = (xmit->tail + 1) & - (UART_XMIT_SIZE - 1); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->port.icount.tx++; if (uart_circ_empty(xmit)) break; @@ -395,8 +394,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) continue; } - if (uart_handle_sysrq_char - (&sport->port, (unsigned char)rx)) + if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) continue; if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { @@ -471,26 +469,26 @@ static unsigned int imx_tx_empty(struct uart_port *port) */ static unsigned int imx_get_mctrl(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; - unsigned int tmp = TIOCM_DSR | TIOCM_CAR; + struct imx_port *sport = (struct imx_port *)port; + unsigned int tmp = TIOCM_DSR | TIOCM_CAR; - if (readl(sport->port.membase + USR1) & USR1_RTSS) - tmp |= TIOCM_CTS; + if (readl(sport->port.membase + USR1) & USR1_RTSS) + tmp |= TIOCM_CTS; - if (readl(sport->port.membase + UCR2) & UCR2_CTS) - tmp |= TIOCM_RTS; + if (readl(sport->port.membase + UCR2) & UCR2_CTS) + tmp |= TIOCM_RTS; - return tmp; + return tmp; } static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = (struct imx_port *)port; unsigned long temp; temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; - if (mctrl & TIOCM_RTS) + if (mctrl & TIOCM_RTS) temp |= UCR2_CTS; writel(temp, sport->port.membase + UCR2); @@ -1072,22 +1070,22 @@ static struct uart_driver imx_reg = { static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) { - struct imx_port *sport = platform_get_drvdata(dev); + struct imx_port *sport = platform_get_drvdata(dev); - if (sport) - uart_suspend_port(&imx_reg, &sport->port); + if (sport) + uart_suspend_port(&imx_reg, &sport->port); - return 0; + return 0; } static int serial_imx_resume(struct platform_device *dev) { - struct imx_port *sport = platform_get_drvdata(dev); + struct imx_port *sport = platform_get_drvdata(dev); - if (sport) - uart_resume_port(&imx_reg, &sport->port); + if (sport) + uart_resume_port(&imx_reg, &sport->port); - return 0; + return 0; } static int serial_imx_probe(struct platform_device *pdev) @@ -1143,7 +1141,7 @@ static int serial_imx_probe(struct platform_device *pdev) imx_ports[pdev->id] = sport; pdata = pdev->dev.platform_data; - if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) + if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) sport->have_rtscts = 1; if (pdata->init) { @@ -1193,13 +1191,13 @@ static int serial_imx_remove(struct platform_device *pdev) } static struct platform_driver serial_imx_driver = { - .probe = serial_imx_probe, - .remove = serial_imx_remove, + .probe = serial_imx_probe, + .remove = serial_imx_remove, .suspend = serial_imx_suspend, .resume = serial_imx_resume, .driver = { - .name = "imx-uart", + .name = "imx-uart", .owner = THIS_MODULE, }, }; -- cgit v1.1 From 26bbb3ff1ff6163d6a233055766e26af8054a212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Thu, 11 Jun 2009 14:36:29 +0100 Subject: imx: serial: fix one bit field type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "have_rtscts" is assigned 1, while it is declared int:1, two's complement, which can hold 0 and -1 only. The code works, as the upper bits are cut off, and tests are done against 0 only. Nonetheless, correctly declaring the bit field as unsigned int:1 renders the code more robust. Signed-off-by: Daniel Glöckner Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 76c8fa1..6b8f12f4 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -211,7 +211,7 @@ struct imx_port { struct timer_list timer; unsigned int old_status; int txirq,rxirq,rtsirq; - int have_rtscts:1; + unsigned int have_rtscts:1; struct clk *clk; }; -- cgit v1.1 From 977757311e50dc5d832c9fef34e7555411f7ccd8 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 11 Jun 2009 14:37:19 +0100 Subject: imx: serial: notify higher layers in case xmit IRQ was not called upper layers, namely line discipline, need to be notified when transmission of more data is possible. For spurious cases, where IRQ handling does not supply notification for sure, it is given additionally here, when data has just been transmitted and space in the buffer will most probably be available. Signed-off-by: Fabian Godehardt Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 6b8f12f4..49f2e12 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -308,6 +308,9 @@ static inline void imx_transmit_buffer(struct imx_port *sport) break; } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + if (uart_circ_empty(xmit)) imx_stop_tx(&sport->port); } -- cgit v1.1 From 2e1463922a35584c863f71d4021e1e71f76eaed0 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 11 Jun 2009 14:38:38 +0100 Subject: imx: serial: be sure to stop xmit upon shutdown needed to avoid continued transmission by hardware while software already shuts down, which might cause dangling characters to show up in hardware queues when restarting the device. Signed-off-by: Fabian Godehardt Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 49f2e12..e6c2ba2 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -634,6 +634,10 @@ static void imx_shutdown(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_TXEN); + writel(temp, sport->port.membase + UCR2); + /* * Stop our timer. */ -- cgit v1.1 From 9f322ad064f9210e7d472dfe77e702274d5c9dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Thu, 11 Jun 2009 14:39:21 +0100 Subject: imx: serial: handle initialisation failure correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit correctly de-initialise device when setting up failed, call to pdata->exit() was missing. Signed-off-by: Daniel Glöckner Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index e6c2ba2..cbd4f32 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1157,10 +1157,15 @@ static int serial_imx_probe(struct platform_device *pdev) goto clkput; } - uart_add_one_port(&imx_reg, &sport->port); + ret = uart_add_one_port(&imx_reg, &sport->port); + if (ret) + goto deinit; platform_set_drvdata(pdev, &sport->port); return 0; +deinit: + if (pdata->exit) + pdata->exit(pdev); clkput: clk_put(sport->clk); clk_disable(sport->clk); -- cgit v1.1 From 534fca068ec8063ec8b67626b3eb34ba6ec86967 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Thu, 11 Jun 2009 14:52:23 +0100 Subject: imx: serial: use rational library function for calculation of numerator and denominator used in baud rate setting, use generic library function for optimum settings. Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index cbd4f32..0de81f7 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -670,7 +671,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, unsigned long flags; unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - unsigned int div, num, denom, ufcr; + unsigned int div, ufcr; + unsigned long num, denom; /* * If we don't support modem control lines, don't allow @@ -772,32 +774,20 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, if (!div) div = 1; - num = baud; - denom = port->uartclk / div / 16; + rational_best_approximation(16 * div * baud, sport->port.uartclk, + 1 << 16, 1 << 16, &num, &denom); - /* shift num and denom right until they fit into 16 bits */ - while (num > 0x10000 || denom > 0x10000) { - num >>= 1; - denom >>= 1; - } - if (num > 0) - num -= 1; - if (denom > 0) - denom -= 1; - - writel(num, sport->port.membase + UBIR); - writel(denom, sport->port.membase + UBMR); - - if (div == 7) - div = 6; /* 6 in RFDIV means divide by 7 */ - else - div = 6 - div; + num -= 1; + denom -= 1; ufcr = readl(sport->port.membase + UFCR); ufcr = (ufcr & (~UFCR_RFDIV)) | (div << 7); writel(ufcr, sport->port.membase + UFCR); + writel(num, sport->port.membase + UBIR); + writel(denom, sport->port.membase + UBMR); + #ifdef ONEMS writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); #endif -- cgit v1.1 From b6e4913834cd032082e5c76dfade61050212dc98 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 11 Jun 2009 14:53:18 +0100 Subject: imx: serial: add IrDA support to serial driver Using the iMX serial driver with an IrDA device needs extra peripheral settings and specific timing depending on the transmitter circuitry used. Signed-off-by: Fabian Godehardt Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 176 insertions(+), 19 deletions(-) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 0de81f7..8c79e8c 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -8,6 +8,9 @@ * Author: Sascha Hauer * Copyright (C) 2004 Pengutronix * + * Copyright (C) 2009 emlix GmbH + * Author: Fabian Godehardt (added IrDA support for iMX) + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,6 +44,7 @@ #include #include #include +#include #include #include @@ -149,6 +153,7 @@ #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ #define USR1_RTSS (1<<14) /* RTS pin status */ @@ -213,9 +218,19 @@ struct imx_port { unsigned int old_status; int txirq,rxirq,rtsirq; unsigned int have_rtscts:1; + unsigned int use_irda:1; + unsigned int irda_inv_rx:1; + unsigned int irda_inv_tx:1; + unsigned short trcv_delay; /* transceiver delay */ struct clk *clk; }; +#ifdef CONFIG_IRDA +#define USE_IRDA(sport) ((sport)->use_irda) +#else +#define USE_IRDA(sport) (0) +#endif + /* * Handle any change of modem status signal since we were last called. */ @@ -269,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (USE_IRDA(sport)) { + /* half duplex - wait for end of transmission */ + int n = 256; + while ((--n > 0) && + !(readl(sport->port.membase + USR2) & USR2_TXDC)) { + udelay(5); + barrier(); + } + /* + * irda transceiver - wait a bit more to avoid + * cutoff, hardware dependent + */ + udelay(sport->trcv_delay); + + /* + * half duplex - reactivate receive mode, + * flush receive pipe echo crap + */ + if (readl(sport->port.membase + USR2) & USR2_TXDC) { + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_TCEN); + writel(temp, sport->port.membase + UCR4); + + while (readl(sport->port.membase + URXD0) & + URXD_CHARRDY) + barrier(); + + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_DREN; + writel(temp, sport->port.membase + UCR4); + } + return; + } + temp = readl(sport->port.membase + UCR1); writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); } @@ -324,9 +381,30 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (USE_IRDA(sport)) { + /* half duplex in IrDA mode; have to disable receive mode */ + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_DREN); + writel(temp, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RRDYEN); + writel(temp, sport->port.membase + UCR1); + } + temp = readl(sport->port.membase + UCR1); writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_TRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_TCEN; + writel(temp, sport->port.membase + UCR4); + } + if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) imx_transmit_buffer(sport); } @@ -536,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) 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); + val |= UFCR_RFDIV_REG(ufcr_rfdiv); writel(val, sport->port.membase + UFCR); @@ -560,8 +633,24 @@ static int imx_startup(struct uart_port *port) * requesting IRQs */ temp = readl(sport->port.membase + UCR4); + + if (USE_IRDA(sport)) + temp |= UCR4_IRSC; + writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); + if (USE_IRDA(sport)) { + /* reset fifo's and state machines */ + int i = 100; + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && + (--i > 0)) { + udelay(1); + } + } + /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. @@ -577,12 +666,16 @@ static int imx_startup(struct uart_port *port) if (retval) goto error_out2; - retval = request_irq(sport->rtsirq, imx_rtsint, - (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - DRIVER_NAME, sport); - if (retval) - goto error_out3; + /* do not use RTS IRQ on IrDA */ + if (!USE_IRDA(sport)) { + retval = request_irq(sport->rtsirq, imx_rtsint, + (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + DRIVER_NAME, sport); + if (retval) + goto error_out3; + } } else { retval = request_irq(sport->port.irq, imx_int, 0, DRIVER_NAME, sport); @@ -599,18 +692,49 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; + + if (USE_IRDA(sport)) { + temp |= UCR1_IREN; + temp &= ~(UCR1_RTSDEN); + } + writel(temp, sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR2); temp |= (UCR2_RXEN | UCR2_TXEN); writel(temp, sport->port.membase + UCR2); + if (USE_IRDA(sport)) { + /* clear RX-FIFO */ + int i = 64; + while ((--i > 0) && + (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { + barrier(); + } + } + #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 temp = readl(sport->port.membase + UCR3); temp |= UCR3_RXDMUXSEL; writel(temp, sport->port.membase + UCR3); #endif + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR4); + if (sport->irda_inv_rx) + temp |= UCR4_INVR; + else + temp &= ~(UCR4_INVR); + writel(temp | UCR4_DREN, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR3); + if (sport->irda_inv_tx) + temp |= UCR3_INVT; + else + temp &= ~(UCR3_INVT); + writel(temp, sport->port.membase + UCR3); + } + /* * Enable modem status interrupts */ @@ -618,6 +742,16 @@ static int imx_startup(struct uart_port *port) imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock,flags); + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + sport->irda_inv_rx = pdata->irda_inv_rx; + sport->irda_inv_tx = pdata->irda_inv_tx; + sport->trcv_delay = pdata->transceiver_delay; + if (pdata->irda_enable) + pdata->irda_enable(1); + } + return 0; error_out3: @@ -639,6 +773,13 @@ static void imx_shutdown(struct uart_port *port) temp &= ~(UCR2_TXEN); writel(temp, sport->port.membase + UCR2); + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + if (pdata->irda_enable) + pdata->irda_enable(0); + } + /* * Stop our timer. */ @@ -648,7 +789,8 @@ static void imx_shutdown(struct uart_port *port) * Free the interrupts */ if (sport->txirq > 0) { - free_irq(sport->rtsirq, sport); + if (!USE_IRDA(sport)) + free_irq(sport->rtsirq, sport); free_irq(sport->txirq, sport); free_irq(sport->rxirq, sport); } else @@ -660,6 +802,9 @@ static void imx_shutdown(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + if (USE_IRDA(sport)) + temp &= ~(UCR1_IREN); + writel(temp, sport->port.membase + UCR1); } @@ -768,11 +913,19 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) + if (USE_IRDA(sport)) { + /* + * use maximum available submodule frequency to + * avoid missing short pulses due to low sampling rate + */ div = 1; + } else { + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) + div = 1; + } rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); @@ -781,8 +934,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, denom -= 1; ufcr = readl(sport->port.membase + UFCR); - ufcr = (ufcr & (~UFCR_RFDIV)) | - (div << 7); + ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); writel(ufcr, sport->port.membase + UFCR); writel(num, sport->port.membase + UBIR); @@ -1141,6 +1293,11 @@ static int serial_imx_probe(struct platform_device *pdev) if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) sport->have_rtscts = 1; +#ifdef CONFIG_IRDA + if (pdata && (pdata->flags & IMXUART_IRDA)) + sport->use_irda = 1; +#endif + if (pdata->init) { ret = pdata->init(pdev); if (ret) -- cgit v1.1 From d7f8d437bda0ec409e26cffb846bc28a40603ee3 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Thu, 11 Jun 2009 14:55:22 +0100 Subject: imx: serial: use tty_encode_baud_rate to set true rate real baud rate may be different from the one requested. for upper layers, set the nearest value to the real rate in favour of the rate previously requested. Signed-off-by: Oskar Schirmer Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/serial/imx.c') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 8c79e8c..7b5d1de 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -818,6 +818,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int div, ufcr; unsigned long num, denom; + uint64_t tdiv64; /* * If we don't support modem control lines, don't allow @@ -930,6 +931,12 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); + tdiv64 = sport->port.uartclk; + tdiv64 *= num; + do_div(tdiv64, denom * 16 * div); + tty_encode_baud_rate(sport->port.info->port.tty, + (speed_t)tdiv64, (speed_t)tdiv64); + num -= 1; denom -= 1; -- cgit v1.1