diff options
Diffstat (limited to 'drivers/serial/imx.c')
-rw-r--r-- | drivers/serial/imx.c | 309 |
1 files changed, 234 insertions, 75 deletions
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 9f460b175c50..285b414f3054 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c | |||
@@ -8,6 +8,9 @@ | |||
8 | * Author: Sascha Hauer <sascha@saschahauer.de> | 8 | * Author: Sascha Hauer <sascha@saschahauer.de> |
9 | * Copyright (C) 2004 Pengutronix | 9 | * Copyright (C) 2004 Pengutronix |
10 | * | 10 | * |
11 | * Copyright (C) 2009 emlix GmbH | ||
12 | * Author: Fabian Godehardt (added IrDA support for iMX) | ||
13 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 16 | * the Free Software Foundation; either version 2 of the License, or |
@@ -41,6 +44,8 @@ | |||
41 | #include <linux/serial_core.h> | 44 | #include <linux/serial_core.h> |
42 | #include <linux/serial.h> | 45 | #include <linux/serial.h> |
43 | #include <linux/clk.h> | 46 | #include <linux/clk.h> |
47 | #include <linux/delay.h> | ||
48 | #include <linux/rational.h> | ||
44 | 49 | ||
45 | #include <asm/io.h> | 50 | #include <asm/io.h> |
46 | #include <asm/irq.h> | 51 | #include <asm/irq.h> |
@@ -66,7 +71,7 @@ | |||
66 | #define ONEMS 0xb0 /* One Millisecond register */ | 71 | #define ONEMS 0xb0 /* One Millisecond register */ |
67 | #define UTS 0xb4 /* UART Test Register */ | 72 | #define UTS 0xb4 /* UART Test Register */ |
68 | #endif | 73 | #endif |
69 | #if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) | 74 | #ifdef CONFIG_ARCH_MX1 |
70 | #define BIPR1 0xb0 /* Incremental Preset Register 1 */ | 75 | #define BIPR1 0xb0 /* Incremental Preset Register 1 */ |
71 | #define BIPR2 0xb4 /* Incremental Preset Register 2 */ | 76 | #define BIPR2 0xb4 /* Incremental Preset Register 2 */ |
72 | #define BIPR3 0xb8 /* Incremental Preset Register 3 */ | 77 | #define BIPR3 0xb8 /* Incremental Preset Register 3 */ |
@@ -96,7 +101,7 @@ | |||
96 | #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ | 101 | #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ |
97 | #define UCR1_SNDBRK (1<<4) /* Send break */ | 102 | #define UCR1_SNDBRK (1<<4) /* Send break */ |
98 | #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ | 103 | #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ |
99 | #if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) | 104 | #ifdef CONFIG_ARCH_MX1 |
100 | #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ | 105 | #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ |
101 | #endif | 106 | #endif |
102 | #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2 | 107 | #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2 |
@@ -127,7 +132,7 @@ | |||
127 | #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ | 132 | #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ |
128 | #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ | 133 | #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ |
129 | #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ | 134 | #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ |
130 | #ifdef CONFIG_ARCH_IMX | 135 | #ifdef CONFIG_ARCH_MX1 |
131 | #define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ | 136 | #define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ |
132 | #define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ | 137 | #define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ |
133 | #endif | 138 | #endif |
@@ -148,6 +153,7 @@ | |||
148 | #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ | 153 | #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ |
149 | #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ | 154 | #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ |
150 | #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ | 155 | #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ |
156 | #define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) | ||
151 | #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ | 157 | #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ |
152 | #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ | 158 | #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ |
153 | #define USR1_RTSS (1<<14) /* RTS pin status */ | 159 | #define USR1_RTSS (1<<14) /* RTS pin status */ |
@@ -180,13 +186,6 @@ | |||
180 | #define UTS_SOFTRST (1<<0) /* Software reset */ | 186 | #define UTS_SOFTRST (1<<0) /* Software reset */ |
181 | 187 | ||
182 | /* We've been assigned a range on the "Low-density serial ports" major */ | 188 | /* We've been assigned a range on the "Low-density serial ports" major */ |
183 | #ifdef CONFIG_ARCH_IMX | ||
184 | #define SERIAL_IMX_MAJOR 204 | ||
185 | #define MINOR_START 41 | ||
186 | #define DEV_NAME "ttySMX" | ||
187 | #define MAX_INTERNAL_IRQ IMX_IRQS | ||
188 | #endif | ||
189 | |||
190 | #ifdef CONFIG_ARCH_MXC | 189 | #ifdef CONFIG_ARCH_MXC |
191 | #define SERIAL_IMX_MAJOR 207 | 190 | #define SERIAL_IMX_MAJOR 207 |
192 | #define MINOR_START 16 | 191 | #define MINOR_START 16 |
@@ -211,10 +210,20 @@ struct imx_port { | |||
211 | struct timer_list timer; | 210 | struct timer_list timer; |
212 | unsigned int old_status; | 211 | unsigned int old_status; |
213 | int txirq,rxirq,rtsirq; | 212 | int txirq,rxirq,rtsirq; |
214 | int have_rtscts:1; | 213 | unsigned int have_rtscts:1; |
214 | unsigned int use_irda:1; | ||
215 | unsigned int irda_inv_rx:1; | ||
216 | unsigned int irda_inv_tx:1; | ||
217 | unsigned short trcv_delay; /* transceiver delay */ | ||
215 | struct clk *clk; | 218 | struct clk *clk; |
216 | }; | 219 | }; |
217 | 220 | ||
221 | #ifdef CONFIG_IRDA | ||
222 | #define USE_IRDA(sport) ((sport)->use_irda) | ||
223 | #else | ||
224 | #define USE_IRDA(sport) (0) | ||
225 | #endif | ||
226 | |||
218 | /* | 227 | /* |
219 | * Handle any change of modem status signal since we were last called. | 228 | * Handle any change of modem status signal since we were last called. |
220 | */ | 229 | */ |
@@ -268,6 +277,48 @@ static void imx_stop_tx(struct uart_port *port) | |||
268 | struct imx_port *sport = (struct imx_port *)port; | 277 | struct imx_port *sport = (struct imx_port *)port; |
269 | unsigned long temp; | 278 | unsigned long temp; |
270 | 279 | ||
280 | if (USE_IRDA(sport)) { | ||
281 | /* half duplex - wait for end of transmission */ | ||
282 | int n = 256; | ||
283 | while ((--n > 0) && | ||
284 | !(readl(sport->port.membase + USR2) & USR2_TXDC)) { | ||
285 | udelay(5); | ||
286 | barrier(); | ||
287 | } | ||
288 | /* | ||
289 | * irda transceiver - wait a bit more to avoid | ||
290 | * cutoff, hardware dependent | ||
291 | */ | ||
292 | udelay(sport->trcv_delay); | ||
293 | |||
294 | /* | ||
295 | * half duplex - reactivate receive mode, | ||
296 | * flush receive pipe echo crap | ||
297 | */ | ||
298 | if (readl(sport->port.membase + USR2) & USR2_TXDC) { | ||
299 | temp = readl(sport->port.membase + UCR1); | ||
300 | temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); | ||
301 | writel(temp, sport->port.membase + UCR1); | ||
302 | |||
303 | temp = readl(sport->port.membase + UCR4); | ||
304 | temp &= ~(UCR4_TCEN); | ||
305 | writel(temp, sport->port.membase + UCR4); | ||
306 | |||
307 | while (readl(sport->port.membase + URXD0) & | ||
308 | URXD_CHARRDY) | ||
309 | barrier(); | ||
310 | |||
311 | temp = readl(sport->port.membase + UCR1); | ||
312 | temp |= UCR1_RRDYEN; | ||
313 | writel(temp, sport->port.membase + UCR1); | ||
314 | |||
315 | temp = readl(sport->port.membase + UCR4); | ||
316 | temp |= UCR4_DREN; | ||
317 | writel(temp, sport->port.membase + UCR4); | ||
318 | } | ||
319 | return; | ||
320 | } | ||
321 | |||
271 | temp = readl(sport->port.membase + UCR1); | 322 | temp = readl(sport->port.membase + UCR1); |
272 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); | 323 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); |
273 | } | 324 | } |
@@ -302,13 +353,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport) | |||
302 | /* send xmit->buf[xmit->tail] | 353 | /* send xmit->buf[xmit->tail] |
303 | * out the port here */ | 354 | * out the port here */ |
304 | writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); | 355 | writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); |
305 | xmit->tail = (xmit->tail + 1) & | 356 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
306 | (UART_XMIT_SIZE - 1); | ||
307 | sport->port.icount.tx++; | 357 | sport->port.icount.tx++; |
308 | if (uart_circ_empty(xmit)) | 358 | if (uart_circ_empty(xmit)) |
309 | break; | 359 | break; |
310 | } | 360 | } |
311 | 361 | ||
362 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
363 | uart_write_wakeup(&sport->port); | ||
364 | |||
312 | if (uart_circ_empty(xmit)) | 365 | if (uart_circ_empty(xmit)) |
313 | imx_stop_tx(&sport->port); | 366 | imx_stop_tx(&sport->port); |
314 | } | 367 | } |
@@ -321,9 +374,30 @@ static void imx_start_tx(struct uart_port *port) | |||
321 | struct imx_port *sport = (struct imx_port *)port; | 374 | struct imx_port *sport = (struct imx_port *)port; |
322 | unsigned long temp; | 375 | unsigned long temp; |
323 | 376 | ||
377 | if (USE_IRDA(sport)) { | ||
378 | /* half duplex in IrDA mode; have to disable receive mode */ | ||
379 | temp = readl(sport->port.membase + UCR4); | ||
380 | temp &= ~(UCR4_DREN); | ||
381 | writel(temp, sport->port.membase + UCR4); | ||
382 | |||
383 | temp = readl(sport->port.membase + UCR1); | ||
384 | temp &= ~(UCR1_RRDYEN); | ||
385 | writel(temp, sport->port.membase + UCR1); | ||
386 | } | ||
387 | |||
324 | temp = readl(sport->port.membase + UCR1); | 388 | temp = readl(sport->port.membase + UCR1); |
325 | writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); | 389 | writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); |
326 | 390 | ||
391 | if (USE_IRDA(sport)) { | ||
392 | temp = readl(sport->port.membase + UCR1); | ||
393 | temp |= UCR1_TRDYEN; | ||
394 | writel(temp, sport->port.membase + UCR1); | ||
395 | |||
396 | temp = readl(sport->port.membase + UCR4); | ||
397 | temp |= UCR4_TCEN; | ||
398 | writel(temp, sport->port.membase + UCR4); | ||
399 | } | ||
400 | |||
327 | if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) | 401 | if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) |
328 | imx_transmit_buffer(sport); | 402 | imx_transmit_buffer(sport); |
329 | } | 403 | } |
@@ -395,8 +469,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) | |||
395 | continue; | 469 | continue; |
396 | } | 470 | } |
397 | 471 | ||
398 | if (uart_handle_sysrq_char | 472 | if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) |
399 | (&sport->port, (unsigned char)rx)) | ||
400 | continue; | 473 | continue; |
401 | 474 | ||
402 | if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { | 475 | if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { |
@@ -471,26 +544,26 @@ static unsigned int imx_tx_empty(struct uart_port *port) | |||
471 | */ | 544 | */ |
472 | static unsigned int imx_get_mctrl(struct uart_port *port) | 545 | static unsigned int imx_get_mctrl(struct uart_port *port) |
473 | { | 546 | { |
474 | struct imx_port *sport = (struct imx_port *)port; | 547 | struct imx_port *sport = (struct imx_port *)port; |
475 | unsigned int tmp = TIOCM_DSR | TIOCM_CAR; | 548 | unsigned int tmp = TIOCM_DSR | TIOCM_CAR; |
476 | 549 | ||
477 | if (readl(sport->port.membase + USR1) & USR1_RTSS) | 550 | if (readl(sport->port.membase + USR1) & USR1_RTSS) |
478 | tmp |= TIOCM_CTS; | 551 | tmp |= TIOCM_CTS; |
479 | 552 | ||
480 | if (readl(sport->port.membase + UCR2) & UCR2_CTS) | 553 | if (readl(sport->port.membase + UCR2) & UCR2_CTS) |
481 | tmp |= TIOCM_RTS; | 554 | tmp |= TIOCM_RTS; |
482 | 555 | ||
483 | return tmp; | 556 | return tmp; |
484 | } | 557 | } |
485 | 558 | ||
486 | static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) | 559 | static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) |
487 | { | 560 | { |
488 | struct imx_port *sport = (struct imx_port *)port; | 561 | struct imx_port *sport = (struct imx_port *)port; |
489 | unsigned long temp; | 562 | unsigned long temp; |
490 | 563 | ||
491 | temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; | 564 | temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; |
492 | 565 | ||
493 | if (mctrl & TIOCM_RTS) | 566 | if (mctrl & TIOCM_RTS) |
494 | temp |= UCR2_CTS; | 567 | temp |= UCR2_CTS; |
495 | 568 | ||
496 | writel(temp, sport->port.membase + UCR2); | 569 | writel(temp, sport->port.membase + UCR2); |
@@ -534,12 +607,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) | |||
534 | if(!ufcr_rfdiv) | 607 | if(!ufcr_rfdiv) |
535 | ufcr_rfdiv = 1; | 608 | ufcr_rfdiv = 1; |
536 | 609 | ||
537 | if(ufcr_rfdiv >= 7) | 610 | val |= UFCR_RFDIV_REG(ufcr_rfdiv); |
538 | ufcr_rfdiv = 6; | ||
539 | else | ||
540 | ufcr_rfdiv = 6 - ufcr_rfdiv; | ||
541 | |||
542 | val |= UFCR_RFDIV & (ufcr_rfdiv << 7); | ||
543 | 611 | ||
544 | writel(val, sport->port.membase + UFCR); | 612 | writel(val, sport->port.membase + UFCR); |
545 | 613 | ||
@@ -558,8 +626,24 @@ static int imx_startup(struct uart_port *port) | |||
558 | * requesting IRQs | 626 | * requesting IRQs |
559 | */ | 627 | */ |
560 | temp = readl(sport->port.membase + UCR4); | 628 | temp = readl(sport->port.membase + UCR4); |
629 | |||
630 | if (USE_IRDA(sport)) | ||
631 | temp |= UCR4_IRSC; | ||
632 | |||
561 | writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); | 633 | writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); |
562 | 634 | ||
635 | if (USE_IRDA(sport)) { | ||
636 | /* reset fifo's and state machines */ | ||
637 | int i = 100; | ||
638 | temp = readl(sport->port.membase + UCR2); | ||
639 | temp &= ~UCR2_SRST; | ||
640 | writel(temp, sport->port.membase + UCR2); | ||
641 | while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && | ||
642 | (--i > 0)) { | ||
643 | udelay(1); | ||
644 | } | ||
645 | } | ||
646 | |||
563 | /* | 647 | /* |
564 | * Allocate the IRQ(s) i.MX1 has three interrupts whereas later | 648 | * Allocate the IRQ(s) i.MX1 has three interrupts whereas later |
565 | * chips only have one interrupt. | 649 | * chips only have one interrupt. |
@@ -575,12 +659,16 @@ static int imx_startup(struct uart_port *port) | |||
575 | if (retval) | 659 | if (retval) |
576 | goto error_out2; | 660 | goto error_out2; |
577 | 661 | ||
578 | retval = request_irq(sport->rtsirq, imx_rtsint, | 662 | /* do not use RTS IRQ on IrDA */ |
579 | (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : | 663 | if (!USE_IRDA(sport)) { |
580 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 664 | retval = request_irq(sport->rtsirq, imx_rtsint, |
581 | DRIVER_NAME, sport); | 665 | (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : |
582 | if (retval) | 666 | IRQF_TRIGGER_FALLING | |
583 | goto error_out3; | 667 | IRQF_TRIGGER_RISING, |
668 | DRIVER_NAME, sport); | ||
669 | if (retval) | ||
670 | goto error_out3; | ||
671 | } | ||
584 | } else { | 672 | } else { |
585 | retval = request_irq(sport->port.irq, imx_int, 0, | 673 | retval = request_irq(sport->port.irq, imx_int, 0, |
586 | DRIVER_NAME, sport); | 674 | DRIVER_NAME, sport); |
@@ -597,18 +685,49 @@ static int imx_startup(struct uart_port *port) | |||
597 | 685 | ||
598 | temp = readl(sport->port.membase + UCR1); | 686 | temp = readl(sport->port.membase + UCR1); |
599 | temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; | 687 | temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; |
688 | |||
689 | if (USE_IRDA(sport)) { | ||
690 | temp |= UCR1_IREN; | ||
691 | temp &= ~(UCR1_RTSDEN); | ||
692 | } | ||
693 | |||
600 | writel(temp, sport->port.membase + UCR1); | 694 | writel(temp, sport->port.membase + UCR1); |
601 | 695 | ||
602 | temp = readl(sport->port.membase + UCR2); | 696 | temp = readl(sport->port.membase + UCR2); |
603 | temp |= (UCR2_RXEN | UCR2_TXEN); | 697 | temp |= (UCR2_RXEN | UCR2_TXEN); |
604 | writel(temp, sport->port.membase + UCR2); | 698 | writel(temp, sport->port.membase + UCR2); |
605 | 699 | ||
700 | if (USE_IRDA(sport)) { | ||
701 | /* clear RX-FIFO */ | ||
702 | int i = 64; | ||
703 | while ((--i > 0) && | ||
704 | (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { | ||
705 | barrier(); | ||
706 | } | ||
707 | } | ||
708 | |||
606 | #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 | 709 | #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 |
607 | temp = readl(sport->port.membase + UCR3); | 710 | temp = readl(sport->port.membase + UCR3); |
608 | temp |= UCR3_RXDMUXSEL; | 711 | temp |= UCR3_RXDMUXSEL; |
609 | writel(temp, sport->port.membase + UCR3); | 712 | writel(temp, sport->port.membase + UCR3); |
610 | #endif | 713 | #endif |
611 | 714 | ||
715 | if (USE_IRDA(sport)) { | ||
716 | temp = readl(sport->port.membase + UCR4); | ||
717 | if (sport->irda_inv_rx) | ||
718 | temp |= UCR4_INVR; | ||
719 | else | ||
720 | temp &= ~(UCR4_INVR); | ||
721 | writel(temp | UCR4_DREN, sport->port.membase + UCR4); | ||
722 | |||
723 | temp = readl(sport->port.membase + UCR3); | ||
724 | if (sport->irda_inv_tx) | ||
725 | temp |= UCR3_INVT; | ||
726 | else | ||
727 | temp &= ~(UCR3_INVT); | ||
728 | writel(temp, sport->port.membase + UCR3); | ||
729 | } | ||
730 | |||
612 | /* | 731 | /* |
613 | * Enable modem status interrupts | 732 | * Enable modem status interrupts |
614 | */ | 733 | */ |
@@ -616,6 +735,16 @@ static int imx_startup(struct uart_port *port) | |||
616 | imx_enable_ms(&sport->port); | 735 | imx_enable_ms(&sport->port); |
617 | spin_unlock_irqrestore(&sport->port.lock,flags); | 736 | spin_unlock_irqrestore(&sport->port.lock,flags); |
618 | 737 | ||
738 | if (USE_IRDA(sport)) { | ||
739 | struct imxuart_platform_data *pdata; | ||
740 | pdata = sport->port.dev->platform_data; | ||
741 | sport->irda_inv_rx = pdata->irda_inv_rx; | ||
742 | sport->irda_inv_tx = pdata->irda_inv_tx; | ||
743 | sport->trcv_delay = pdata->transceiver_delay; | ||
744 | if (pdata->irda_enable) | ||
745 | pdata->irda_enable(1); | ||
746 | } | ||
747 | |||
619 | return 0; | 748 | return 0; |
620 | 749 | ||
621 | error_out3: | 750 | error_out3: |
@@ -633,6 +762,17 @@ static void imx_shutdown(struct uart_port *port) | |||
633 | struct imx_port *sport = (struct imx_port *)port; | 762 | struct imx_port *sport = (struct imx_port *)port; |
634 | unsigned long temp; | 763 | unsigned long temp; |
635 | 764 | ||
765 | temp = readl(sport->port.membase + UCR2); | ||
766 | temp &= ~(UCR2_TXEN); | ||
767 | writel(temp, sport->port.membase + UCR2); | ||
768 | |||
769 | if (USE_IRDA(sport)) { | ||
770 | struct imxuart_platform_data *pdata; | ||
771 | pdata = sport->port.dev->platform_data; | ||
772 | if (pdata->irda_enable) | ||
773 | pdata->irda_enable(0); | ||
774 | } | ||
775 | |||
636 | /* | 776 | /* |
637 | * Stop our timer. | 777 | * Stop our timer. |
638 | */ | 778 | */ |
@@ -642,7 +782,8 @@ static void imx_shutdown(struct uart_port *port) | |||
642 | * Free the interrupts | 782 | * Free the interrupts |
643 | */ | 783 | */ |
644 | if (sport->txirq > 0) { | 784 | if (sport->txirq > 0) { |
645 | free_irq(sport->rtsirq, sport); | 785 | if (!USE_IRDA(sport)) |
786 | free_irq(sport->rtsirq, sport); | ||
646 | free_irq(sport->txirq, sport); | 787 | free_irq(sport->txirq, sport); |
647 | free_irq(sport->rxirq, sport); | 788 | free_irq(sport->rxirq, sport); |
648 | } else | 789 | } else |
@@ -654,6 +795,9 @@ static void imx_shutdown(struct uart_port *port) | |||
654 | 795 | ||
655 | temp = readl(sport->port.membase + UCR1); | 796 | temp = readl(sport->port.membase + UCR1); |
656 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); | 797 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); |
798 | if (USE_IRDA(sport)) | ||
799 | temp &= ~(UCR1_IREN); | ||
800 | |||
657 | writel(temp, sport->port.membase + UCR1); | 801 | writel(temp, sport->port.membase + UCR1); |
658 | } | 802 | } |
659 | 803 | ||
@@ -665,7 +809,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
665 | unsigned long flags; | 809 | unsigned long flags; |
666 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; | 810 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; |
667 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; | 811 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; |
668 | unsigned int div, num, denom, ufcr; | 812 | unsigned int div, ufcr; |
813 | unsigned long num, denom; | ||
814 | uint64_t tdiv64; | ||
669 | 815 | ||
670 | /* | 816 | /* |
671 | * If we don't support modem control lines, don't allow | 817 | * If we don't support modem control lines, don't allow |
@@ -761,38 +907,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
761 | sport->port.membase + UCR2); | 907 | sport->port.membase + UCR2); |
762 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); | 908 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); |
763 | 909 | ||
764 | div = sport->port.uartclk / (baud * 16); | 910 | if (USE_IRDA(sport)) { |
765 | if (div > 7) | 911 | /* |
766 | div = 7; | 912 | * use maximum available submodule frequency to |
767 | if (!div) | 913 | * avoid missing short pulses due to low sampling rate |
914 | */ | ||
768 | div = 1; | 915 | div = 1; |
769 | 916 | } else { | |
770 | num = baud; | 917 | div = sport->port.uartclk / (baud * 16); |
771 | denom = port->uartclk / div / 16; | 918 | if (div > 7) |
772 | 919 | div = 7; | |
773 | /* shift num and denom right until they fit into 16 bits */ | 920 | if (!div) |
774 | while (num > 0x10000 || denom > 0x10000) { | 921 | div = 1; |
775 | num >>= 1; | ||
776 | denom >>= 1; | ||
777 | } | 922 | } |
778 | if (num > 0) | ||
779 | num -= 1; | ||
780 | if (denom > 0) | ||
781 | denom -= 1; | ||
782 | 923 | ||
783 | writel(num, sport->port.membase + UBIR); | 924 | rational_best_approximation(16 * div * baud, sport->port.uartclk, |
784 | writel(denom, sport->port.membase + UBMR); | 925 | 1 << 16, 1 << 16, &num, &denom); |
785 | 926 | ||
786 | if (div == 7) | 927 | tdiv64 = sport->port.uartclk; |
787 | div = 6; /* 6 in RFDIV means divide by 7 */ | 928 | tdiv64 *= num; |
788 | else | 929 | do_div(tdiv64, denom * 16 * div); |
789 | div = 6 - div; | 930 | tty_encode_baud_rate(sport->port.info->port.tty, |
931 | (speed_t)tdiv64, (speed_t)tdiv64); | ||
932 | |||
933 | num -= 1; | ||
934 | denom -= 1; | ||
790 | 935 | ||
791 | ufcr = readl(sport->port.membase + UFCR); | 936 | ufcr = readl(sport->port.membase + UFCR); |
792 | ufcr = (ufcr & (~UFCR_RFDIV)) | | 937 | ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); |
793 | (div << 7); | ||
794 | writel(ufcr, sport->port.membase + UFCR); | 938 | writel(ufcr, sport->port.membase + UFCR); |
795 | 939 | ||
940 | writel(num, sport->port.membase + UBIR); | ||
941 | writel(denom, sport->port.membase + UBMR); | ||
942 | |||
796 | #ifdef ONEMS | 943 | #ifdef ONEMS |
797 | writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); | 944 | writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); |
798 | #endif | 945 | #endif |
@@ -1031,6 +1178,8 @@ imx_console_setup(struct console *co, char *options) | |||
1031 | if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) | 1178 | if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) |
1032 | co->index = 0; | 1179 | co->index = 0; |
1033 | sport = imx_ports[co->index]; | 1180 | sport = imx_ports[co->index]; |
1181 | if(sport == NULL) | ||
1182 | return -ENODEV; | ||
1034 | 1183 | ||
1035 | if (options) | 1184 | if (options) |
1036 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 1185 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
@@ -1070,22 +1219,22 @@ static struct uart_driver imx_reg = { | |||
1070 | 1219 | ||
1071 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) | 1220 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) |
1072 | { | 1221 | { |
1073 | struct imx_port *sport = platform_get_drvdata(dev); | 1222 | struct imx_port *sport = platform_get_drvdata(dev); |
1074 | 1223 | ||
1075 | if (sport) | 1224 | if (sport) |
1076 | uart_suspend_port(&imx_reg, &sport->port); | 1225 | uart_suspend_port(&imx_reg, &sport->port); |
1077 | 1226 | ||
1078 | return 0; | 1227 | return 0; |
1079 | } | 1228 | } |
1080 | 1229 | ||
1081 | static int serial_imx_resume(struct platform_device *dev) | 1230 | static int serial_imx_resume(struct platform_device *dev) |
1082 | { | 1231 | { |
1083 | struct imx_port *sport = platform_get_drvdata(dev); | 1232 | struct imx_port *sport = platform_get_drvdata(dev); |
1084 | 1233 | ||
1085 | if (sport) | 1234 | if (sport) |
1086 | uart_resume_port(&imx_reg, &sport->port); | 1235 | uart_resume_port(&imx_reg, &sport->port); |
1087 | 1236 | ||
1088 | return 0; | 1237 | return 0; |
1089 | } | 1238 | } |
1090 | 1239 | ||
1091 | static int serial_imx_probe(struct platform_device *pdev) | 1240 | static int serial_imx_probe(struct platform_device *pdev) |
@@ -1141,19 +1290,29 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
1141 | imx_ports[pdev->id] = sport; | 1290 | imx_ports[pdev->id] = sport; |
1142 | 1291 | ||
1143 | pdata = pdev->dev.platform_data; | 1292 | pdata = pdev->dev.platform_data; |
1144 | if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) | 1293 | if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) |
1145 | sport->have_rtscts = 1; | 1294 | sport->have_rtscts = 1; |
1146 | 1295 | ||
1296 | #ifdef CONFIG_IRDA | ||
1297 | if (pdata && (pdata->flags & IMXUART_IRDA)) | ||
1298 | sport->use_irda = 1; | ||
1299 | #endif | ||
1300 | |||
1147 | if (pdata->init) { | 1301 | if (pdata->init) { |
1148 | ret = pdata->init(pdev); | 1302 | ret = pdata->init(pdev); |
1149 | if (ret) | 1303 | if (ret) |
1150 | goto clkput; | 1304 | goto clkput; |
1151 | } | 1305 | } |
1152 | 1306 | ||
1153 | uart_add_one_port(&imx_reg, &sport->port); | 1307 | ret = uart_add_one_port(&imx_reg, &sport->port); |
1308 | if (ret) | ||
1309 | goto deinit; | ||
1154 | platform_set_drvdata(pdev, &sport->port); | 1310 | platform_set_drvdata(pdev, &sport->port); |
1155 | 1311 | ||
1156 | return 0; | 1312 | return 0; |
1313 | deinit: | ||
1314 | if (pdata->exit) | ||
1315 | pdata->exit(pdev); | ||
1157 | clkput: | 1316 | clkput: |
1158 | clk_put(sport->clk); | 1317 | clk_put(sport->clk); |
1159 | clk_disable(sport->clk); | 1318 | clk_disable(sport->clk); |
@@ -1191,13 +1350,13 @@ static int serial_imx_remove(struct platform_device *pdev) | |||
1191 | } | 1350 | } |
1192 | 1351 | ||
1193 | static struct platform_driver serial_imx_driver = { | 1352 | static struct platform_driver serial_imx_driver = { |
1194 | .probe = serial_imx_probe, | 1353 | .probe = serial_imx_probe, |
1195 | .remove = serial_imx_remove, | 1354 | .remove = serial_imx_remove, |
1196 | 1355 | ||
1197 | .suspend = serial_imx_suspend, | 1356 | .suspend = serial_imx_suspend, |
1198 | .resume = serial_imx_resume, | 1357 | .resume = serial_imx_resume, |
1199 | .driver = { | 1358 | .driver = { |
1200 | .name = "imx-uart", | 1359 | .name = "imx-uart", |
1201 | .owner = THIS_MODULE, | 1360 | .owner = THIS_MODULE, |
1202 | }, | 1361 | }, |
1203 | }; | 1362 | }; |