aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/imx.c
diff options
context:
space:
mode:
authorFabian Godehardt <fg@emlix.com>2009-06-11 09:53:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-11 11:51:08 -0400
commitb6e4913834cd032082e5c76dfade61050212dc98 (patch)
tree21f7c1b454ced01895ee121c4980a54d7e0e02f9 /drivers/serial/imx.c
parent534fca068ec8063ec8b67626b3eb34ba6ec86967 (diff)
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 <fg@emlix.com> Signed-off-by: Oskar Schirmer <os@emlix.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/serial/imx.c')
-rw-r--r--drivers/serial/imx.c195
1 files changed, 176 insertions, 19 deletions
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 0de81f71f884..8c79e8c2fd4e 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,7 @@
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>
44#include <linux/rational.h> 48#include <linux/rational.h>
45 49
46#include <asm/io.h> 50#include <asm/io.h>
@@ -149,6 +153,7 @@
149#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ 153#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
150#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ 154#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
151#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)
152#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ 157#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
153#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ 158#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
154#define USR1_RTSS (1<<14) /* RTS pin status */ 159#define USR1_RTSS (1<<14) /* RTS pin status */
@@ -213,9 +218,19 @@ struct imx_port {
213 unsigned int old_status; 218 unsigned int old_status;
214 int txirq,rxirq,rtsirq; 219 int txirq,rxirq,rtsirq;
215 unsigned 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 */
216 struct clk *clk; 225 struct clk *clk;
217}; 226};
218 227
228#ifdef CONFIG_IRDA
229#define USE_IRDA(sport) ((sport)->use_irda)
230#else
231#define USE_IRDA(sport) (0)
232#endif
233
219/* 234/*
220 * 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.
221 */ 236 */
@@ -269,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port)
269 struct imx_port *sport = (struct imx_port *)port; 284 struct imx_port *sport = (struct imx_port *)port;
270 unsigned long temp; 285 unsigned long temp;
271 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
272 temp = readl(sport->port.membase + UCR1); 329 temp = readl(sport->port.membase + UCR1);
273 writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); 330 writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
274} 331}
@@ -324,9 +381,30 @@ static void imx_start_tx(struct uart_port *port)
324 struct imx_port *sport = (struct imx_port *)port; 381 struct imx_port *sport = (struct imx_port *)port;
325 unsigned long temp; 382 unsigned long temp;
326 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
327 temp = readl(sport->port.membase + UCR1); 395 temp = readl(sport->port.membase + UCR1);
328 writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); 396 writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
329 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
330 if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) 408 if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
331 imx_transmit_buffer(sport); 409 imx_transmit_buffer(sport);
332} 410}
@@ -536,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
536 if(!ufcr_rfdiv) 614 if(!ufcr_rfdiv)
537 ufcr_rfdiv = 1; 615 ufcr_rfdiv = 1;
538 616
539 if(ufcr_rfdiv >= 7) 617 val |= UFCR_RFDIV_REG(ufcr_rfdiv);
540 ufcr_rfdiv = 6;
541 else
542 ufcr_rfdiv = 6 - ufcr_rfdiv;
543
544 val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
545 618
546 writel(val, sport->port.membase + UFCR); 619 writel(val, sport->port.membase + UFCR);
547 620
@@ -560,8 +633,24 @@ static int imx_startup(struct uart_port *port)
560 * requesting IRQs 633 * requesting IRQs
561 */ 634 */
562 temp = readl(sport->port.membase + UCR4); 635 temp = readl(sport->port.membase + UCR4);
636
637 if (USE_IRDA(sport))
638 temp |= UCR4_IRSC;
639
563 writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); 640 writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
564 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
565 /* 654 /*
566 * Allocate the IRQ(s) i.MX1 has three interrupts whereas later 655 * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
567 * chips only have one interrupt. 656 * chips only have one interrupt.
@@ -577,12 +666,16 @@ static int imx_startup(struct uart_port *port)
577 if (retval) 666 if (retval)
578 goto error_out2; 667 goto error_out2;
579 668
580 retval = request_irq(sport->rtsirq, imx_rtsint, 669 /* do not use RTS IRQ on IrDA */
581 (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : 670 if (!USE_IRDA(sport)) {
582 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 671 retval = request_irq(sport->rtsirq, imx_rtsint,
583 DRIVER_NAME, sport); 672 (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
584 if (retval) 673 IRQF_TRIGGER_FALLING |
585 goto error_out3; 674 IRQF_TRIGGER_RISING,
675 DRIVER_NAME, sport);
676 if (retval)
677 goto error_out3;
678 }
586 } else { 679 } else {
587 retval = request_irq(sport->port.irq, imx_int, 0, 680 retval = request_irq(sport->port.irq, imx_int, 0,
588 DRIVER_NAME, sport); 681 DRIVER_NAME, sport);
@@ -599,18 +692,49 @@ static int imx_startup(struct uart_port *port)
599 692
600 temp = readl(sport->port.membase + UCR1); 693 temp = readl(sport->port.membase + UCR1);
601 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
602 writel(temp, sport->port.membase + UCR1); 701 writel(temp, sport->port.membase + UCR1);
603 702
604 temp = readl(sport->port.membase + UCR2); 703 temp = readl(sport->port.membase + UCR2);
605 temp |= (UCR2_RXEN | UCR2_TXEN); 704 temp |= (UCR2_RXEN | UCR2_TXEN);
606 writel(temp, sport->port.membase + UCR2); 705 writel(temp, sport->port.membase + UCR2);
607 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
608#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 716#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
609 temp = readl(sport->port.membase + UCR3); 717 temp = readl(sport->port.membase + UCR3);
610 temp |= UCR3_RXDMUXSEL; 718 temp |= UCR3_RXDMUXSEL;
611 writel(temp, sport->port.membase + UCR3); 719 writel(temp, sport->port.membase + UCR3);
612#endif 720#endif
613 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
614 /* 738 /*
615 * Enable modem status interrupts 739 * Enable modem status interrupts
616 */ 740 */
@@ -618,6 +742,16 @@ static int imx_startup(struct uart_port *port)
618 imx_enable_ms(&sport->port); 742 imx_enable_ms(&sport->port);
619 spin_unlock_irqrestore(&sport->port.lock,flags); 743 spin_unlock_irqrestore(&sport->port.lock,flags);
620 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
621 return 0; 755 return 0;
622 756
623error_out3: 757error_out3:
@@ -639,6 +773,13 @@ static void imx_shutdown(struct uart_port *port)
639 temp &= ~(UCR2_TXEN); 773 temp &= ~(UCR2_TXEN);
640 writel(temp, sport->port.membase + UCR2); 774 writel(temp, sport->port.membase + UCR2);
641 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
642 /* 783 /*
643 * Stop our timer. 784 * Stop our timer.
644 */ 785 */
@@ -648,7 +789,8 @@ static void imx_shutdown(struct uart_port *port)
648 * Free the interrupts 789 * Free the interrupts
649 */ 790 */
650 if (sport->txirq > 0) { 791 if (sport->txirq > 0) {
651 free_irq(sport->rtsirq, sport); 792 if (!USE_IRDA(sport))
793 free_irq(sport->rtsirq, sport);
652 free_irq(sport->txirq, sport); 794 free_irq(sport->txirq, sport);
653 free_irq(sport->rxirq, sport); 795 free_irq(sport->rxirq, sport);
654 } else 796 } else
@@ -660,6 +802,9 @@ static void imx_shutdown(struct uart_port *port)
660 802
661 temp = readl(sport->port.membase + UCR1); 803 temp = readl(sport->port.membase + UCR1);
662 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
663 writel(temp, sport->port.membase + UCR1); 808 writel(temp, sport->port.membase + UCR1);
664} 809}
665 810
@@ -768,11 +913,19 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
768 sport->port.membase + UCR2); 913 sport->port.membase + UCR2);
769 old_txrxen &= (UCR2_TXEN | UCR2_RXEN); 914 old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
770 915
771 div = sport->port.uartclk / (baud * 16); 916 if (USE_IRDA(sport)) {
772 if (div > 7) 917 /*
773 div = 7; 918 * use maximum available submodule frequency to
774 if (!div) 919 * avoid missing short pulses due to low sampling rate
920 */
775 div = 1; 921 div = 1;
922 } else {
923 div = sport->port.uartclk / (baud * 16);
924 if (div > 7)
925 div = 7;
926 if (!div)
927 div = 1;
928 }
776 929
777 rational_best_approximation(16 * div * baud, sport->port.uartclk, 930 rational_best_approximation(16 * div * baud, sport->port.uartclk,
778 1 << 16, 1 << 16, &num, &denom); 931 1 << 16, 1 << 16, &num, &denom);
@@ -781,8 +934,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
781 denom -= 1; 934 denom -= 1;
782 935
783 ufcr = readl(sport->port.membase + UFCR); 936 ufcr = readl(sport->port.membase + UFCR);
784 ufcr = (ufcr & (~UFCR_RFDIV)) | 937 ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
785 (div << 7);
786 writel(ufcr, sport->port.membase + UFCR); 938 writel(ufcr, sport->port.membase + UFCR);
787 939
788 writel(num, sport->port.membase + UBIR); 940 writel(num, sport->port.membase + UBIR);
@@ -1141,6 +1293,11 @@ static int serial_imx_probe(struct platform_device *pdev)
1141 if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) 1293 if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
1142 sport->have_rtscts = 1; 1294 sport->have_rtscts = 1;
1143 1295
1296#ifdef CONFIG_IRDA
1297 if (pdata && (pdata->flags & IMXUART_IRDA))
1298 sport->use_irda = 1;
1299#endif
1300
1144 if (pdata->init) { 1301 if (pdata->init) {
1145 ret = pdata->init(pdev); 1302 ret = pdata->init(pdev);
1146 if (ret) 1303 if (ret)