diff options
Diffstat (limited to 'drivers/serial/imx.c')
-rw-r--r-- | drivers/serial/imx.c | 296 |
1 files changed, 231 insertions, 65 deletions
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 9f460b175c50..7b5d1de9cfe3 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> |
@@ -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 */ |
@@ -211,10 +217,20 @@ struct imx_port { | |||
211 | struct timer_list timer; | 217 | struct timer_list timer; |
212 | unsigned int old_status; | 218 | unsigned int old_status; |
213 | int txirq,rxirq,rtsirq; | 219 | int txirq,rxirq,rtsirq; |
214 | int have_rtscts:1; | 220 | unsigned int have_rtscts:1; |
221 | unsigned int use_irda:1; | ||
222 | unsigned int irda_inv_rx:1; | ||
223 | unsigned int irda_inv_tx:1; | ||
224 | unsigned short trcv_delay; /* transceiver delay */ | ||
215 | struct clk *clk; | 225 | struct clk *clk; |
216 | }; | 226 | }; |
217 | 227 | ||
228 | #ifdef CONFIG_IRDA | ||
229 | #define USE_IRDA(sport) ((sport)->use_irda) | ||
230 | #else | ||
231 | #define USE_IRDA(sport) (0) | ||
232 | #endif | ||
233 | |||
218 | /* | 234 | /* |
219 | * Handle any change of modem status signal since we were last called. | 235 | * Handle any change of modem status signal since we were last called. |
220 | */ | 236 | */ |
@@ -268,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port) | |||
268 | struct imx_port *sport = (struct imx_port *)port; | 284 | struct imx_port *sport = (struct imx_port *)port; |
269 | unsigned long temp; | 285 | unsigned long temp; |
270 | 286 | ||
287 | if (USE_IRDA(sport)) { | ||
288 | /* half duplex - wait for end of transmission */ | ||
289 | int n = 256; | ||
290 | while ((--n > 0) && | ||
291 | !(readl(sport->port.membase + USR2) & USR2_TXDC)) { | ||
292 | udelay(5); | ||
293 | barrier(); | ||
294 | } | ||
295 | /* | ||
296 | * irda transceiver - wait a bit more to avoid | ||
297 | * cutoff, hardware dependent | ||
298 | */ | ||
299 | udelay(sport->trcv_delay); | ||
300 | |||
301 | /* | ||
302 | * half duplex - reactivate receive mode, | ||
303 | * flush receive pipe echo crap | ||
304 | */ | ||
305 | if (readl(sport->port.membase + USR2) & USR2_TXDC) { | ||
306 | temp = readl(sport->port.membase + UCR1); | ||
307 | temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); | ||
308 | writel(temp, sport->port.membase + UCR1); | ||
309 | |||
310 | temp = readl(sport->port.membase + UCR4); | ||
311 | temp &= ~(UCR4_TCEN); | ||
312 | writel(temp, sport->port.membase + UCR4); | ||
313 | |||
314 | while (readl(sport->port.membase + URXD0) & | ||
315 | URXD_CHARRDY) | ||
316 | barrier(); | ||
317 | |||
318 | temp = readl(sport->port.membase + UCR1); | ||
319 | temp |= UCR1_RRDYEN; | ||
320 | writel(temp, sport->port.membase + UCR1); | ||
321 | |||
322 | temp = readl(sport->port.membase + UCR4); | ||
323 | temp |= UCR4_DREN; | ||
324 | writel(temp, sport->port.membase + UCR4); | ||
325 | } | ||
326 | return; | ||
327 | } | ||
328 | |||
271 | temp = readl(sport->port.membase + UCR1); | 329 | temp = readl(sport->port.membase + UCR1); |
272 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); | 330 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); |
273 | } | 331 | } |
@@ -302,13 +360,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport) | |||
302 | /* send xmit->buf[xmit->tail] | 360 | /* send xmit->buf[xmit->tail] |
303 | * out the port here */ | 361 | * out the port here */ |
304 | writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); | 362 | writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); |
305 | xmit->tail = (xmit->tail + 1) & | 363 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
306 | (UART_XMIT_SIZE - 1); | ||
307 | sport->port.icount.tx++; | 364 | sport->port.icount.tx++; |
308 | if (uart_circ_empty(xmit)) | 365 | if (uart_circ_empty(xmit)) |
309 | break; | 366 | break; |
310 | } | 367 | } |
311 | 368 | ||
369 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
370 | uart_write_wakeup(&sport->port); | ||
371 | |||
312 | if (uart_circ_empty(xmit)) | 372 | if (uart_circ_empty(xmit)) |
313 | imx_stop_tx(&sport->port); | 373 | imx_stop_tx(&sport->port); |
314 | } | 374 | } |
@@ -321,9 +381,30 @@ static void imx_start_tx(struct uart_port *port) | |||
321 | struct imx_port *sport = (struct imx_port *)port; | 381 | struct imx_port *sport = (struct imx_port *)port; |
322 | unsigned long temp; | 382 | unsigned long temp; |
323 | 383 | ||
384 | if (USE_IRDA(sport)) { | ||
385 | /* half duplex in IrDA mode; have to disable receive mode */ | ||
386 | temp = readl(sport->port.membase + UCR4); | ||
387 | temp &= ~(UCR4_DREN); | ||
388 | writel(temp, sport->port.membase + UCR4); | ||
389 | |||
390 | temp = readl(sport->port.membase + UCR1); | ||
391 | temp &= ~(UCR1_RRDYEN); | ||
392 | writel(temp, sport->port.membase + UCR1); | ||
393 | } | ||
394 | |||
324 | temp = readl(sport->port.membase + UCR1); | 395 | temp = readl(sport->port.membase + UCR1); |
325 | writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); | 396 | writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); |
326 | 397 | ||
398 | if (USE_IRDA(sport)) { | ||
399 | temp = readl(sport->port.membase + UCR1); | ||
400 | temp |= UCR1_TRDYEN; | ||
401 | writel(temp, sport->port.membase + UCR1); | ||
402 | |||
403 | temp = readl(sport->port.membase + UCR4); | ||
404 | temp |= UCR4_TCEN; | ||
405 | writel(temp, sport->port.membase + UCR4); | ||
406 | } | ||
407 | |||
327 | if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) | 408 | if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) |
328 | imx_transmit_buffer(sport); | 409 | imx_transmit_buffer(sport); |
329 | } | 410 | } |
@@ -395,8 +476,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) | |||
395 | continue; | 476 | continue; |
396 | } | 477 | } |
397 | 478 | ||
398 | if (uart_handle_sysrq_char | 479 | if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) |
399 | (&sport->port, (unsigned char)rx)) | ||
400 | continue; | 480 | continue; |
401 | 481 | ||
402 | if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { | 482 | if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { |
@@ -471,26 +551,26 @@ static unsigned int imx_tx_empty(struct uart_port *port) | |||
471 | */ | 551 | */ |
472 | static unsigned int imx_get_mctrl(struct uart_port *port) | 552 | static unsigned int imx_get_mctrl(struct uart_port *port) |
473 | { | 553 | { |
474 | struct imx_port *sport = (struct imx_port *)port; | 554 | struct imx_port *sport = (struct imx_port *)port; |
475 | unsigned int tmp = TIOCM_DSR | TIOCM_CAR; | 555 | unsigned int tmp = TIOCM_DSR | TIOCM_CAR; |
476 | 556 | ||
477 | if (readl(sport->port.membase + USR1) & USR1_RTSS) | 557 | if (readl(sport->port.membase + USR1) & USR1_RTSS) |
478 | tmp |= TIOCM_CTS; | 558 | tmp |= TIOCM_CTS; |
479 | 559 | ||
480 | if (readl(sport->port.membase + UCR2) & UCR2_CTS) | 560 | if (readl(sport->port.membase + UCR2) & UCR2_CTS) |
481 | tmp |= TIOCM_RTS; | 561 | tmp |= TIOCM_RTS; |
482 | 562 | ||
483 | return tmp; | 563 | return tmp; |
484 | } | 564 | } |
485 | 565 | ||
486 | static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) | 566 | static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) |
487 | { | 567 | { |
488 | struct imx_port *sport = (struct imx_port *)port; | 568 | struct imx_port *sport = (struct imx_port *)port; |
489 | unsigned long temp; | 569 | unsigned long temp; |
490 | 570 | ||
491 | temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; | 571 | temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; |
492 | 572 | ||
493 | if (mctrl & TIOCM_RTS) | 573 | if (mctrl & TIOCM_RTS) |
494 | temp |= UCR2_CTS; | 574 | temp |= UCR2_CTS; |
495 | 575 | ||
496 | writel(temp, sport->port.membase + UCR2); | 576 | writel(temp, sport->port.membase + UCR2); |
@@ -534,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) | |||
534 | if(!ufcr_rfdiv) | 614 | if(!ufcr_rfdiv) |
535 | ufcr_rfdiv = 1; | 615 | ufcr_rfdiv = 1; |
536 | 616 | ||
537 | if(ufcr_rfdiv >= 7) | 617 | 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 | 618 | ||
544 | writel(val, sport->port.membase + UFCR); | 619 | writel(val, sport->port.membase + UFCR); |
545 | 620 | ||
@@ -558,8 +633,24 @@ static int imx_startup(struct uart_port *port) | |||
558 | * requesting IRQs | 633 | * requesting IRQs |
559 | */ | 634 | */ |
560 | temp = readl(sport->port.membase + UCR4); | 635 | temp = readl(sport->port.membase + UCR4); |
636 | |||
637 | if (USE_IRDA(sport)) | ||
638 | temp |= UCR4_IRSC; | ||
639 | |||
561 | writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); | 640 | writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); |
562 | 641 | ||
642 | if (USE_IRDA(sport)) { | ||
643 | /* reset fifo's and state machines */ | ||
644 | int i = 100; | ||
645 | temp = readl(sport->port.membase + UCR2); | ||
646 | temp &= ~UCR2_SRST; | ||
647 | writel(temp, sport->port.membase + UCR2); | ||
648 | while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && | ||
649 | (--i > 0)) { | ||
650 | udelay(1); | ||
651 | } | ||
652 | } | ||
653 | |||
563 | /* | 654 | /* |
564 | * Allocate the IRQ(s) i.MX1 has three interrupts whereas later | 655 | * Allocate the IRQ(s) i.MX1 has three interrupts whereas later |
565 | * chips only have one interrupt. | 656 | * chips only have one interrupt. |
@@ -575,12 +666,16 @@ static int imx_startup(struct uart_port *port) | |||
575 | if (retval) | 666 | if (retval) |
576 | goto error_out2; | 667 | goto error_out2; |
577 | 668 | ||
578 | retval = request_irq(sport->rtsirq, imx_rtsint, | 669 | /* do not use RTS IRQ on IrDA */ |
579 | (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : | 670 | if (!USE_IRDA(sport)) { |
580 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 671 | retval = request_irq(sport->rtsirq, imx_rtsint, |
581 | DRIVER_NAME, sport); | 672 | (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : |
582 | if (retval) | 673 | IRQF_TRIGGER_FALLING | |
583 | goto error_out3; | 674 | IRQF_TRIGGER_RISING, |
675 | DRIVER_NAME, sport); | ||
676 | if (retval) | ||
677 | goto error_out3; | ||
678 | } | ||
584 | } else { | 679 | } else { |
585 | retval = request_irq(sport->port.irq, imx_int, 0, | 680 | retval = request_irq(sport->port.irq, imx_int, 0, |
586 | DRIVER_NAME, sport); | 681 | DRIVER_NAME, sport); |
@@ -597,18 +692,49 @@ static int imx_startup(struct uart_port *port) | |||
597 | 692 | ||
598 | temp = readl(sport->port.membase + UCR1); | 693 | temp = readl(sport->port.membase + UCR1); |
599 | temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; | 694 | temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; |
695 | |||
696 | if (USE_IRDA(sport)) { | ||
697 | temp |= UCR1_IREN; | ||
698 | temp &= ~(UCR1_RTSDEN); | ||
699 | } | ||
700 | |||
600 | writel(temp, sport->port.membase + UCR1); | 701 | writel(temp, sport->port.membase + UCR1); |
601 | 702 | ||
602 | temp = readl(sport->port.membase + UCR2); | 703 | temp = readl(sport->port.membase + UCR2); |
603 | temp |= (UCR2_RXEN | UCR2_TXEN); | 704 | temp |= (UCR2_RXEN | UCR2_TXEN); |
604 | writel(temp, sport->port.membase + UCR2); | 705 | writel(temp, sport->port.membase + UCR2); |
605 | 706 | ||
707 | if (USE_IRDA(sport)) { | ||
708 | /* clear RX-FIFO */ | ||
709 | int i = 64; | ||
710 | while ((--i > 0) && | ||
711 | (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { | ||
712 | barrier(); | ||
713 | } | ||
714 | } | ||
715 | |||
606 | #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 | 716 | #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 |
607 | temp = readl(sport->port.membase + UCR3); | 717 | temp = readl(sport->port.membase + UCR3); |
608 | temp |= UCR3_RXDMUXSEL; | 718 | temp |= UCR3_RXDMUXSEL; |
609 | writel(temp, sport->port.membase + UCR3); | 719 | writel(temp, sport->port.membase + UCR3); |
610 | #endif | 720 | #endif |
611 | 721 | ||
722 | if (USE_IRDA(sport)) { | ||
723 | temp = readl(sport->port.membase + UCR4); | ||
724 | if (sport->irda_inv_rx) | ||
725 | temp |= UCR4_INVR; | ||
726 | else | ||
727 | temp &= ~(UCR4_INVR); | ||
728 | writel(temp | UCR4_DREN, sport->port.membase + UCR4); | ||
729 | |||
730 | temp = readl(sport->port.membase + UCR3); | ||
731 | if (sport->irda_inv_tx) | ||
732 | temp |= UCR3_INVT; | ||
733 | else | ||
734 | temp &= ~(UCR3_INVT); | ||
735 | writel(temp, sport->port.membase + UCR3); | ||
736 | } | ||
737 | |||
612 | /* | 738 | /* |
613 | * Enable modem status interrupts | 739 | * Enable modem status interrupts |
614 | */ | 740 | */ |
@@ -616,6 +742,16 @@ static int imx_startup(struct uart_port *port) | |||
616 | imx_enable_ms(&sport->port); | 742 | imx_enable_ms(&sport->port); |
617 | spin_unlock_irqrestore(&sport->port.lock,flags); | 743 | spin_unlock_irqrestore(&sport->port.lock,flags); |
618 | 744 | ||
745 | if (USE_IRDA(sport)) { | ||
746 | struct imxuart_platform_data *pdata; | ||
747 | pdata = sport->port.dev->platform_data; | ||
748 | sport->irda_inv_rx = pdata->irda_inv_rx; | ||
749 | sport->irda_inv_tx = pdata->irda_inv_tx; | ||
750 | sport->trcv_delay = pdata->transceiver_delay; | ||
751 | if (pdata->irda_enable) | ||
752 | pdata->irda_enable(1); | ||
753 | } | ||
754 | |||
619 | return 0; | 755 | return 0; |
620 | 756 | ||
621 | error_out3: | 757 | error_out3: |
@@ -633,6 +769,17 @@ static void imx_shutdown(struct uart_port *port) | |||
633 | struct imx_port *sport = (struct imx_port *)port; | 769 | struct imx_port *sport = (struct imx_port *)port; |
634 | unsigned long temp; | 770 | unsigned long temp; |
635 | 771 | ||
772 | temp = readl(sport->port.membase + UCR2); | ||
773 | temp &= ~(UCR2_TXEN); | ||
774 | writel(temp, sport->port.membase + UCR2); | ||
775 | |||
776 | if (USE_IRDA(sport)) { | ||
777 | struct imxuart_platform_data *pdata; | ||
778 | pdata = sport->port.dev->platform_data; | ||
779 | if (pdata->irda_enable) | ||
780 | pdata->irda_enable(0); | ||
781 | } | ||
782 | |||
636 | /* | 783 | /* |
637 | * Stop our timer. | 784 | * Stop our timer. |
638 | */ | 785 | */ |
@@ -642,7 +789,8 @@ static void imx_shutdown(struct uart_port *port) | |||
642 | * Free the interrupts | 789 | * Free the interrupts |
643 | */ | 790 | */ |
644 | if (sport->txirq > 0) { | 791 | if (sport->txirq > 0) { |
645 | free_irq(sport->rtsirq, sport); | 792 | if (!USE_IRDA(sport)) |
793 | free_irq(sport->rtsirq, sport); | ||
646 | free_irq(sport->txirq, sport); | 794 | free_irq(sport->txirq, sport); |
647 | free_irq(sport->rxirq, sport); | 795 | free_irq(sport->rxirq, sport); |
648 | } else | 796 | } else |
@@ -654,6 +802,9 @@ static void imx_shutdown(struct uart_port *port) | |||
654 | 802 | ||
655 | temp = readl(sport->port.membase + UCR1); | 803 | temp = readl(sport->port.membase + UCR1); |
656 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); | 804 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); |
805 | if (USE_IRDA(sport)) | ||
806 | temp &= ~(UCR1_IREN); | ||
807 | |||
657 | writel(temp, sport->port.membase + UCR1); | 808 | writel(temp, sport->port.membase + UCR1); |
658 | } | 809 | } |
659 | 810 | ||
@@ -665,7 +816,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
665 | unsigned long flags; | 816 | unsigned long flags; |
666 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; | 817 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; |
667 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; | 818 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; |
668 | unsigned int div, num, denom, ufcr; | 819 | unsigned int div, ufcr; |
820 | unsigned long num, denom; | ||
821 | uint64_t tdiv64; | ||
669 | 822 | ||
670 | /* | 823 | /* |
671 | * If we don't support modem control lines, don't allow | 824 | * If we don't support modem control lines, don't allow |
@@ -761,38 +914,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
761 | sport->port.membase + UCR2); | 914 | sport->port.membase + UCR2); |
762 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); | 915 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); |
763 | 916 | ||
764 | div = sport->port.uartclk / (baud * 16); | 917 | if (USE_IRDA(sport)) { |
765 | if (div > 7) | 918 | /* |
766 | div = 7; | 919 | * use maximum available submodule frequency to |
767 | if (!div) | 920 | * avoid missing short pulses due to low sampling rate |
921 | */ | ||
768 | div = 1; | 922 | div = 1; |
769 | 923 | } else { | |
770 | num = baud; | 924 | div = sport->port.uartclk / (baud * 16); |
771 | denom = port->uartclk / div / 16; | 925 | if (div > 7) |
772 | 926 | div = 7; | |
773 | /* shift num and denom right until they fit into 16 bits */ | 927 | if (!div) |
774 | while (num > 0x10000 || denom > 0x10000) { | 928 | div = 1; |
775 | num >>= 1; | ||
776 | denom >>= 1; | ||
777 | } | 929 | } |
778 | if (num > 0) | ||
779 | num -= 1; | ||
780 | if (denom > 0) | ||
781 | denom -= 1; | ||
782 | 930 | ||
783 | writel(num, sport->port.membase + UBIR); | 931 | rational_best_approximation(16 * div * baud, sport->port.uartclk, |
784 | writel(denom, sport->port.membase + UBMR); | 932 | 1 << 16, 1 << 16, &num, &denom); |
785 | 933 | ||
786 | if (div == 7) | 934 | tdiv64 = sport->port.uartclk; |
787 | div = 6; /* 6 in RFDIV means divide by 7 */ | 935 | tdiv64 *= num; |
788 | else | 936 | do_div(tdiv64, denom * 16 * div); |
789 | div = 6 - div; | 937 | tty_encode_baud_rate(sport->port.info->port.tty, |
938 | (speed_t)tdiv64, (speed_t)tdiv64); | ||
939 | |||
940 | num -= 1; | ||
941 | denom -= 1; | ||
790 | 942 | ||
791 | ufcr = readl(sport->port.membase + UFCR); | 943 | ufcr = readl(sport->port.membase + UFCR); |
792 | ufcr = (ufcr & (~UFCR_RFDIV)) | | 944 | ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); |
793 | (div << 7); | ||
794 | writel(ufcr, sport->port.membase + UFCR); | 945 | writel(ufcr, sport->port.membase + UFCR); |
795 | 946 | ||
947 | writel(num, sport->port.membase + UBIR); | ||
948 | writel(denom, sport->port.membase + UBMR); | ||
949 | |||
796 | #ifdef ONEMS | 950 | #ifdef ONEMS |
797 | writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); | 951 | writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); |
798 | #endif | 952 | #endif |
@@ -1031,6 +1185,8 @@ imx_console_setup(struct console *co, char *options) | |||
1031 | if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) | 1185 | if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) |
1032 | co->index = 0; | 1186 | co->index = 0; |
1033 | sport = imx_ports[co->index]; | 1187 | sport = imx_ports[co->index]; |
1188 | if(sport == NULL) | ||
1189 | return -ENODEV; | ||
1034 | 1190 | ||
1035 | if (options) | 1191 | if (options) |
1036 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 1192 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
@@ -1070,22 +1226,22 @@ static struct uart_driver imx_reg = { | |||
1070 | 1226 | ||
1071 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) | 1227 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) |
1072 | { | 1228 | { |
1073 | struct imx_port *sport = platform_get_drvdata(dev); | 1229 | struct imx_port *sport = platform_get_drvdata(dev); |
1074 | 1230 | ||
1075 | if (sport) | 1231 | if (sport) |
1076 | uart_suspend_port(&imx_reg, &sport->port); | 1232 | uart_suspend_port(&imx_reg, &sport->port); |
1077 | 1233 | ||
1078 | return 0; | 1234 | return 0; |
1079 | } | 1235 | } |
1080 | 1236 | ||
1081 | static int serial_imx_resume(struct platform_device *dev) | 1237 | static int serial_imx_resume(struct platform_device *dev) |
1082 | { | 1238 | { |
1083 | struct imx_port *sport = platform_get_drvdata(dev); | 1239 | struct imx_port *sport = platform_get_drvdata(dev); |
1084 | 1240 | ||
1085 | if (sport) | 1241 | if (sport) |
1086 | uart_resume_port(&imx_reg, &sport->port); | 1242 | uart_resume_port(&imx_reg, &sport->port); |
1087 | 1243 | ||
1088 | return 0; | 1244 | return 0; |
1089 | } | 1245 | } |
1090 | 1246 | ||
1091 | static int serial_imx_probe(struct platform_device *pdev) | 1247 | static int serial_imx_probe(struct platform_device *pdev) |
@@ -1141,19 +1297,29 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
1141 | imx_ports[pdev->id] = sport; | 1297 | imx_ports[pdev->id] = sport; |
1142 | 1298 | ||
1143 | pdata = pdev->dev.platform_data; | 1299 | pdata = pdev->dev.platform_data; |
1144 | if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) | 1300 | if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) |
1145 | sport->have_rtscts = 1; | 1301 | sport->have_rtscts = 1; |
1146 | 1302 | ||
1303 | #ifdef CONFIG_IRDA | ||
1304 | if (pdata && (pdata->flags & IMXUART_IRDA)) | ||
1305 | sport->use_irda = 1; | ||
1306 | #endif | ||
1307 | |||
1147 | if (pdata->init) { | 1308 | if (pdata->init) { |
1148 | ret = pdata->init(pdev); | 1309 | ret = pdata->init(pdev); |
1149 | if (ret) | 1310 | if (ret) |
1150 | goto clkput; | 1311 | goto clkput; |
1151 | } | 1312 | } |
1152 | 1313 | ||
1153 | uart_add_one_port(&imx_reg, &sport->port); | 1314 | ret = uart_add_one_port(&imx_reg, &sport->port); |
1315 | if (ret) | ||
1316 | goto deinit; | ||
1154 | platform_set_drvdata(pdev, &sport->port); | 1317 | platform_set_drvdata(pdev, &sport->port); |
1155 | 1318 | ||
1156 | return 0; | 1319 | return 0; |
1320 | deinit: | ||
1321 | if (pdata->exit) | ||
1322 | pdata->exit(pdev); | ||
1157 | clkput: | 1323 | clkput: |
1158 | clk_put(sport->clk); | 1324 | clk_put(sport->clk); |
1159 | clk_disable(sport->clk); | 1325 | clk_disable(sport->clk); |
@@ -1191,13 +1357,13 @@ static int serial_imx_remove(struct platform_device *pdev) | |||
1191 | } | 1357 | } |
1192 | 1358 | ||
1193 | static struct platform_driver serial_imx_driver = { | 1359 | static struct platform_driver serial_imx_driver = { |
1194 | .probe = serial_imx_probe, | 1360 | .probe = serial_imx_probe, |
1195 | .remove = serial_imx_remove, | 1361 | .remove = serial_imx_remove, |
1196 | 1362 | ||
1197 | .suspend = serial_imx_suspend, | 1363 | .suspend = serial_imx_suspend, |
1198 | .resume = serial_imx_resume, | 1364 | .resume = serial_imx_resume, |
1199 | .driver = { | 1365 | .driver = { |
1200 | .name = "imx-uart", | 1366 | .name = "imx-uart", |
1201 | .owner = THIS_MODULE, | 1367 | .owner = THIS_MODULE, |
1202 | }, | 1368 | }, |
1203 | }; | 1369 | }; |