diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/amba-pl010.c | 2 | ||||
-rw-r--r-- | drivers/serial/amba-pl011.c | 38 | ||||
-rw-r--r-- | drivers/serial/icom.c | 2 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm.h | 2 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_driver.c | 1 | ||||
-rw-r--r-- | drivers/serial/nwpserial.c | 4 | ||||
-rw-r--r-- | drivers/serial/s3c6400.c | 1 | ||||
-rw-r--r-- | drivers/serial/samsung.c | 61 | ||||
-rw-r--r-- | drivers/serial/samsung.h | 4 |
9 files changed, 101 insertions, 14 deletions
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index e3a5ad5ef1d6..cdc049d4350f 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c | |||
@@ -665,7 +665,7 @@ static struct uart_driver amba_reg = { | |||
665 | .cons = AMBA_CONSOLE, | 665 | .cons = AMBA_CONSOLE, |
666 | }; | 666 | }; |
667 | 667 | ||
668 | static int pl010_probe(struct amba_device *dev, void *id) | 668 | static int pl010_probe(struct amba_device *dev, struct amba_id *id) |
669 | { | 669 | { |
670 | struct uart_amba_port *uap; | 670 | struct uart_amba_port *uap; |
671 | void __iomem *base; | 671 | void __iomem *base; |
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 8b2b9700f3e4..8c5bda27736c 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -70,6 +70,23 @@ struct uart_amba_port { | |||
70 | struct clk *clk; | 70 | struct clk *clk; |
71 | unsigned int im; /* interrupt mask */ | 71 | unsigned int im; /* interrupt mask */ |
72 | unsigned int old_status; | 72 | unsigned int old_status; |
73 | unsigned int ifls; /* vendor-specific */ | ||
74 | }; | ||
75 | |||
76 | /* There is by now at least one vendor with differing details, so handle it */ | ||
77 | struct vendor_data { | ||
78 | unsigned int ifls; | ||
79 | unsigned int fifosize; | ||
80 | }; | ||
81 | |||
82 | static struct vendor_data vendor_arm = { | ||
83 | .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, | ||
84 | .fifosize = 16, | ||
85 | }; | ||
86 | |||
87 | static struct vendor_data vendor_st = { | ||
88 | .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, | ||
89 | .fifosize = 64, | ||
73 | }; | 90 | }; |
74 | 91 | ||
75 | static void pl011_stop_tx(struct uart_port *port) | 92 | static void pl011_stop_tx(struct uart_port *port) |
@@ -360,8 +377,7 @@ static int pl011_startup(struct uart_port *port) | |||
360 | if (retval) | 377 | if (retval) |
361 | goto clk_dis; | 378 | goto clk_dis; |
362 | 379 | ||
363 | writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, | 380 | writew(uap->ifls, uap->port.membase + UART011_IFLS); |
364 | uap->port.membase + UART011_IFLS); | ||
365 | 381 | ||
366 | /* | 382 | /* |
367 | * Provoke TX FIFO interrupt into asserting. | 383 | * Provoke TX FIFO interrupt into asserting. |
@@ -729,9 +745,10 @@ static struct uart_driver amba_reg = { | |||
729 | .cons = AMBA_CONSOLE, | 745 | .cons = AMBA_CONSOLE, |
730 | }; | 746 | }; |
731 | 747 | ||
732 | static int pl011_probe(struct amba_device *dev, void *id) | 748 | static int pl011_probe(struct amba_device *dev, struct amba_id *id) |
733 | { | 749 | { |
734 | struct uart_amba_port *uap; | 750 | struct uart_amba_port *uap; |
751 | struct vendor_data *vendor = id->data; | ||
735 | void __iomem *base; | 752 | void __iomem *base; |
736 | int i, ret; | 753 | int i, ret; |
737 | 754 | ||
@@ -762,12 +779,13 @@ static int pl011_probe(struct amba_device *dev, void *id) | |||
762 | goto unmap; | 779 | goto unmap; |
763 | } | 780 | } |
764 | 781 | ||
782 | uap->ifls = vendor->ifls; | ||
765 | uap->port.dev = &dev->dev; | 783 | uap->port.dev = &dev->dev; |
766 | uap->port.mapbase = dev->res.start; | 784 | uap->port.mapbase = dev->res.start; |
767 | uap->port.membase = base; | 785 | uap->port.membase = base; |
768 | uap->port.iotype = UPIO_MEM; | 786 | uap->port.iotype = UPIO_MEM; |
769 | uap->port.irq = dev->irq[0]; | 787 | uap->port.irq = dev->irq[0]; |
770 | uap->port.fifosize = 16; | 788 | uap->port.fifosize = vendor->fifosize; |
771 | uap->port.ops = &amba_pl011_pops; | 789 | uap->port.ops = &amba_pl011_pops; |
772 | uap->port.flags = UPF_BOOT_AUTOCONF; | 790 | uap->port.flags = UPF_BOOT_AUTOCONF; |
773 | uap->port.line = i; | 791 | uap->port.line = i; |
@@ -812,6 +830,12 @@ static struct amba_id pl011_ids[] __initdata = { | |||
812 | { | 830 | { |
813 | .id = 0x00041011, | 831 | .id = 0x00041011, |
814 | .mask = 0x000fffff, | 832 | .mask = 0x000fffff, |
833 | .data = &vendor_arm, | ||
834 | }, | ||
835 | { | ||
836 | .id = 0x00380802, | ||
837 | .mask = 0x00ffffff, | ||
838 | .data = &vendor_st, | ||
815 | }, | 839 | }, |
816 | { 0, 0 }, | 840 | { 0, 0 }, |
817 | }; | 841 | }; |
@@ -845,7 +869,11 @@ static void __exit pl011_exit(void) | |||
845 | uart_unregister_driver(&amba_reg); | 869 | uart_unregister_driver(&amba_reg); |
846 | } | 870 | } |
847 | 871 | ||
848 | module_init(pl011_init); | 872 | /* |
873 | * While this can be a module, if builtin it's most likely the console | ||
874 | * So let's leave module_exit but move module_init to an earlier place | ||
875 | */ | ||
876 | arch_initcall(pl011_init); | ||
849 | module_exit(pl011_exit); | 877 | module_exit(pl011_exit); |
850 | 878 | ||
851 | MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); | 879 | MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); |
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 6579e2be1dd1..a461b3b2c72d 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c | |||
@@ -1472,8 +1472,8 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) | |||
1472 | 1472 | ||
1473 | free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); | 1473 | free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); |
1474 | iounmap(icom_adapter->base_addr); | 1474 | iounmap(icom_adapter->base_addr); |
1475 | icom_free_adapter(icom_adapter); | ||
1476 | pci_release_regions(icom_adapter->pci_dev); | 1475 | pci_release_regions(icom_adapter->pci_dev); |
1476 | icom_free_adapter(icom_adapter); | ||
1477 | } | 1477 | } |
1478 | 1478 | ||
1479 | static void icom_kref_release(struct kref *kref) | 1479 | static void icom_kref_release(struct kref *kref) |
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index 8871aaa3dba6..c0a3e2734e24 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h | |||
@@ -130,8 +130,6 @@ struct jsm_board | |||
130 | struct pci_dev *pci_dev; | 130 | struct pci_dev *pci_dev; |
131 | u32 maxports; /* MAX ports this board can handle */ | 131 | u32 maxports; /* MAX ports this board can handle */ |
132 | 132 | ||
133 | spinlock_t bd_lock; /* Used to protect board */ | ||
134 | |||
135 | spinlock_t bd_intr_lock; /* Used to protect the poller tasklet and | 133 | spinlock_t bd_intr_lock; /* Used to protect the poller tasklet and |
136 | * the interrupt routine from each other. | 134 | * the interrupt routine from each other. |
137 | */ | 135 | */ |
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c index d2d32a198629..b3604aa322a4 100644 --- a/drivers/serial/jsm/jsm_driver.c +++ b/drivers/serial/jsm/jsm_driver.c | |||
@@ -88,7 +88,6 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device | |||
88 | else | 88 | else |
89 | brd->maxports = 2; | 89 | brd->maxports = 2; |
90 | 90 | ||
91 | spin_lock_init(&brd->bd_lock); | ||
92 | spin_lock_init(&brd->bd_intr_lock); | 91 | spin_lock_init(&brd->bd_intr_lock); |
93 | 92 | ||
94 | /* store which revision we have */ | 93 | /* store which revision we have */ |
diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c index 32f3eaf0d262..9e150b19d726 100644 --- a/drivers/serial/nwpserial.c +++ b/drivers/serial/nwpserial.c | |||
@@ -145,11 +145,13 @@ static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) | |||
145 | ch = dcr_read(up->dcr_host, UART_RX); | 145 | ch = dcr_read(up->dcr_host, UART_RX); |
146 | if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID) | 146 | if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID) |
147 | tty_insert_flip_char(tty, ch, TTY_NORMAL); | 147 | tty_insert_flip_char(tty, ch, TTY_NORMAL); |
148 | } while (dcr_read(up->dcr_host, UART_RX) & UART_LSR_DR); | 148 | } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR); |
149 | 149 | ||
150 | tty_flip_buffer_push(tty); | 150 | tty_flip_buffer_push(tty); |
151 | ret = IRQ_HANDLED; | 151 | ret = IRQ_HANDLED; |
152 | 152 | ||
153 | /* clear interrupt */ | ||
154 | dcr_write(up->dcr_host, UART_IIR, 1); | ||
153 | out: | 155 | out: |
154 | spin_unlock(&up->port.lock); | 156 | spin_unlock(&up->port.lock); |
155 | return ret; | 157 | return ret; |
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c index 06936d13393f..3e3785233682 100644 --- a/drivers/serial/s3c6400.c +++ b/drivers/serial/s3c6400.c | |||
@@ -102,6 +102,7 @@ static struct s3c24xx_uart_info s3c6400_uart_inf = { | |||
102 | .name = "Samsung S3C6400 UART", | 102 | .name = "Samsung S3C6400 UART", |
103 | .type = PORT_S3C6400, | 103 | .type = PORT_S3C6400, |
104 | .fifosize = 64, | 104 | .fifosize = 64, |
105 | .has_divslot = 1, | ||
105 | .rx_fifomask = S3C2440_UFSTAT_RXMASK, | 106 | .rx_fifomask = S3C2440_UFSTAT_RXMASK, |
106 | .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, | 107 | .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, |
107 | .rx_fifofull = S3C2440_UFSTAT_RXFULL, | 108 | .rx_fifofull = S3C2440_UFSTAT_RXFULL, |
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index e06686ae858b..93b5d75db126 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c | |||
@@ -508,6 +508,7 @@ s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c) | |||
508 | struct baud_calc { | 508 | struct baud_calc { |
509 | struct s3c24xx_uart_clksrc *clksrc; | 509 | struct s3c24xx_uart_clksrc *clksrc; |
510 | unsigned int calc; | 510 | unsigned int calc; |
511 | unsigned int divslot; | ||
511 | unsigned int quot; | 512 | unsigned int quot; |
512 | struct clk *src; | 513 | struct clk *src; |
513 | }; | 514 | }; |
@@ -517,6 +518,7 @@ static int s3c24xx_serial_calcbaud(struct baud_calc *calc, | |||
517 | struct s3c24xx_uart_clksrc *clksrc, | 518 | struct s3c24xx_uart_clksrc *clksrc, |
518 | unsigned int baud) | 519 | unsigned int baud) |
519 | { | 520 | { |
521 | struct s3c24xx_uart_port *ourport = to_ourport(port); | ||
520 | unsigned long rate; | 522 | unsigned long rate; |
521 | 523 | ||
522 | calc->src = clk_get(port->dev, clksrc->name); | 524 | calc->src = clk_get(port->dev, clksrc->name); |
@@ -527,8 +529,24 @@ static int s3c24xx_serial_calcbaud(struct baud_calc *calc, | |||
527 | rate /= clksrc->divisor; | 529 | rate /= clksrc->divisor; |
528 | 530 | ||
529 | calc->clksrc = clksrc; | 531 | calc->clksrc = clksrc; |
530 | calc->quot = (rate + (8 * baud)) / (16 * baud); | 532 | |
531 | calc->calc = (rate / (calc->quot * 16)); | 533 | if (ourport->info->has_divslot) { |
534 | unsigned long div = rate / baud; | ||
535 | |||
536 | /* The UDIVSLOT register on the newer UARTs allows us to | ||
537 | * get a divisor adjustment of 1/16th on the baud clock. | ||
538 | * | ||
539 | * We don't keep the UDIVSLOT value (the 16ths we calculated | ||
540 | * by not multiplying the baud by 16) as it is easy enough | ||
541 | * to recalculate. | ||
542 | */ | ||
543 | |||
544 | calc->quot = div / 16; | ||
545 | calc->calc = rate / div; | ||
546 | } else { | ||
547 | calc->quot = (rate + (8 * baud)) / (16 * baud); | ||
548 | calc->calc = (rate / (calc->quot * 16)); | ||
549 | } | ||
532 | 550 | ||
533 | calc->quot--; | 551 | calc->quot--; |
534 | return 1; | 552 | return 1; |
@@ -611,6 +629,30 @@ static unsigned int s3c24xx_serial_getclk(struct uart_port *port, | |||
611 | return best->quot; | 629 | return best->quot; |
612 | } | 630 | } |
613 | 631 | ||
632 | /* udivslot_table[] | ||
633 | * | ||
634 | * This table takes the fractional value of the baud divisor and gives | ||
635 | * the recommended setting for the UDIVSLOT register. | ||
636 | */ | ||
637 | static u16 udivslot_table[16] = { | ||
638 | [0] = 0x0000, | ||
639 | [1] = 0x0080, | ||
640 | [2] = 0x0808, | ||
641 | [3] = 0x0888, | ||
642 | [4] = 0x2222, | ||
643 | [5] = 0x4924, | ||
644 | [6] = 0x4A52, | ||
645 | [7] = 0x54AA, | ||
646 | [8] = 0x5555, | ||
647 | [9] = 0xD555, | ||
648 | [10] = 0xD5D5, | ||
649 | [11] = 0xDDD5, | ||
650 | [12] = 0xDDDD, | ||
651 | [13] = 0xDFDD, | ||
652 | [14] = 0xDFDF, | ||
653 | [15] = 0xFFDF, | ||
654 | }; | ||
655 | |||
614 | static void s3c24xx_serial_set_termios(struct uart_port *port, | 656 | static void s3c24xx_serial_set_termios(struct uart_port *port, |
615 | struct ktermios *termios, | 657 | struct ktermios *termios, |
616 | struct ktermios *old) | 658 | struct ktermios *old) |
@@ -623,6 +665,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, | |||
623 | unsigned int baud, quot; | 665 | unsigned int baud, quot; |
624 | unsigned int ulcon; | 666 | unsigned int ulcon; |
625 | unsigned int umcon; | 667 | unsigned int umcon; |
668 | unsigned int udivslot = 0; | ||
626 | 669 | ||
627 | /* | 670 | /* |
628 | * We don't support modem control lines. | 671 | * We don't support modem control lines. |
@@ -644,6 +687,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, | |||
644 | /* check to see if we need to change clock source */ | 687 | /* check to see if we need to change clock source */ |
645 | 688 | ||
646 | if (ourport->clksrc != clksrc || ourport->baudclk != clk) { | 689 | if (ourport->clksrc != clksrc || ourport->baudclk != clk) { |
690 | dbg("selecting clock %p\n", clk); | ||
647 | s3c24xx_serial_setsource(port, clksrc); | 691 | s3c24xx_serial_setsource(port, clksrc); |
648 | 692 | ||
649 | if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { | 693 | if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { |
@@ -658,6 +702,13 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, | |||
658 | ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; | 702 | ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; |
659 | } | 703 | } |
660 | 704 | ||
705 | if (ourport->info->has_divslot) { | ||
706 | unsigned int div = ourport->baudclk_rate / baud; | ||
707 | |||
708 | udivslot = udivslot_table[div & 15]; | ||
709 | dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); | ||
710 | } | ||
711 | |||
661 | switch (termios->c_cflag & CSIZE) { | 712 | switch (termios->c_cflag & CSIZE) { |
662 | case CS5: | 713 | case CS5: |
663 | dbg("config: 5bits/char\n"); | 714 | dbg("config: 5bits/char\n"); |
@@ -697,12 +748,16 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, | |||
697 | 748 | ||
698 | spin_lock_irqsave(&port->lock, flags); | 749 | spin_lock_irqsave(&port->lock, flags); |
699 | 750 | ||
700 | dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot); | 751 | dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n", |
752 | ulcon, quot, udivslot); | ||
701 | 753 | ||
702 | wr_regl(port, S3C2410_ULCON, ulcon); | 754 | wr_regl(port, S3C2410_ULCON, ulcon); |
703 | wr_regl(port, S3C2410_UBRDIV, quot); | 755 | wr_regl(port, S3C2410_UBRDIV, quot); |
704 | wr_regl(port, S3C2410_UMCON, umcon); | 756 | wr_regl(port, S3C2410_UMCON, umcon); |
705 | 757 | ||
758 | if (ourport->info->has_divslot) | ||
759 | wr_regl(port, S3C2443_DIVSLOT, udivslot); | ||
760 | |||
706 | dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", | 761 | dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", |
707 | rd_regl(port, S3C2410_ULCON), | 762 | rd_regl(port, S3C2410_ULCON), |
708 | rd_regl(port, S3C2410_UCON), | 763 | rd_regl(port, S3C2410_UCON), |
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h index 571d6b90d206..7afb94843a08 100644 --- a/drivers/serial/samsung.h +++ b/drivers/serial/samsung.h | |||
@@ -21,6 +21,10 @@ struct s3c24xx_uart_info { | |||
21 | unsigned long tx_fifoshift; | 21 | unsigned long tx_fifoshift; |
22 | unsigned long tx_fifofull; | 22 | unsigned long tx_fifofull; |
23 | 23 | ||
24 | /* uart port features */ | ||
25 | |||
26 | unsigned int has_divslot:1; | ||
27 | |||
24 | /* clock source control */ | 28 | /* clock source control */ |
25 | 29 | ||
26 | int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk); | 30 | int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk); |