diff options
author | David S. Miller <davem@davemloft.net> | 2009-06-15 06:02:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-15 06:02:23 -0400 |
commit | 9cbc1cb8cd46ce1f7645b9de249b2ce8460129bb (patch) | |
tree | 8d104ec2a459346b99413b0b77421ca7b9936c1a /drivers/serial | |
parent | ca44d6e60f9de26281fda203f58b570e1748c015 (diff) | |
parent | 45e3e1935e2857c54783291107d33323b3ef33c8 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
Documentation/feature-removal-schedule.txt
drivers/scsi/fcoe/fcoe.c
net/core/drop_monitor.c
net/core/net-traces.c
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 22 | ||||
-rw-r--r-- | drivers/serial/8250_gsc.c | 4 | ||||
-rw-r--r-- | drivers/serial/8250_pci.c | 3 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 10 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/amba-pl010.c | 4 | ||||
-rw-r--r-- | drivers/serial/amba-pl011.c | 40 | ||||
-rw-r--r-- | drivers/serial/bfin_5xx.c | 77 | ||||
-rw-r--r-- | drivers/serial/bfin_sport_uart.c | 58 | ||||
-rw-r--r-- | drivers/serial/icom.c | 22 | ||||
-rw-r--r-- | drivers/serial/imx.c | 309 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm.h | 1 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_tty.c | 14 | ||||
-rw-r--r-- | drivers/serial/mpc52xx_uart.c | 2 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 388 | ||||
-rw-r--r-- | drivers/serial/sh-sci.h | 42 | ||||
-rw-r--r-- | drivers/serial/timbuart.c | 526 | ||||
-rw-r--r-- | drivers/serial/timbuart.h | 58 |
18 files changed, 1261 insertions, 320 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index b4b39811b44..fb867a9f55e 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -137,6 +137,7 @@ struct uart_8250_port { | |||
137 | unsigned char mcr; | 137 | unsigned char mcr; |
138 | unsigned char mcr_mask; /* mask of user bits */ | 138 | unsigned char mcr_mask; /* mask of user bits */ |
139 | unsigned char mcr_force; /* mask of forced bits */ | 139 | unsigned char mcr_force; /* mask of forced bits */ |
140 | unsigned char cur_iotype; /* Running I/O type */ | ||
140 | 141 | ||
141 | /* | 142 | /* |
142 | * Some bits in registers are cleared on a read, so they must | 143 | * Some bits in registers are cleared on a read, so they must |
@@ -286,6 +287,13 @@ static const struct serial8250_config uart_config[] = { | |||
286 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, | 287 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, |
287 | .flags = UART_CAP_FIFO, | 288 | .flags = UART_CAP_FIFO, |
288 | }, | 289 | }, |
290 | [PORT_AR7] = { | ||
291 | .name = "AR7", | ||
292 | .fifo_size = 16, | ||
293 | .tx_loadsz = 16, | ||
294 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, | ||
295 | .flags = UART_CAP_FIFO | UART_CAP_AFE, | ||
296 | }, | ||
289 | }; | 297 | }; |
290 | 298 | ||
291 | #if defined (CONFIG_SERIAL_8250_AU1X00) | 299 | #if defined (CONFIG_SERIAL_8250_AU1X00) |
@@ -471,6 +479,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value) | |||
471 | 479 | ||
472 | static void set_io_from_upio(struct uart_port *p) | 480 | static void set_io_from_upio(struct uart_port *p) |
473 | { | 481 | { |
482 | struct uart_8250_port *up = (struct uart_8250_port *)p; | ||
474 | switch (p->iotype) { | 483 | switch (p->iotype) { |
475 | case UPIO_HUB6: | 484 | case UPIO_HUB6: |
476 | p->serial_in = hub6_serial_in; | 485 | p->serial_in = hub6_serial_in; |
@@ -509,6 +518,8 @@ static void set_io_from_upio(struct uart_port *p) | |||
509 | p->serial_out = io_serial_out; | 518 | p->serial_out = io_serial_out; |
510 | break; | 519 | break; |
511 | } | 520 | } |
521 | /* Remember loaded iotype */ | ||
522 | up->cur_iotype = p->iotype; | ||
512 | } | 523 | } |
513 | 524 | ||
514 | static void | 525 | static void |
@@ -1937,6 +1948,9 @@ static int serial8250_startup(struct uart_port *port) | |||
1937 | up->capabilities = uart_config[up->port.type].flags; | 1948 | up->capabilities = uart_config[up->port.type].flags; |
1938 | up->mcr = 0; | 1949 | up->mcr = 0; |
1939 | 1950 | ||
1951 | if (up->port.iotype != up->cur_iotype) | ||
1952 | set_io_from_upio(port); | ||
1953 | |||
1940 | if (up->port.type == PORT_16C950) { | 1954 | if (up->port.type == PORT_16C950) { |
1941 | /* Wake up and initialize UART */ | 1955 | /* Wake up and initialize UART */ |
1942 | up->acr = 0; | 1956 | up->acr = 0; |
@@ -2563,6 +2577,9 @@ static void serial8250_config_port(struct uart_port *port, int flags) | |||
2563 | if (ret < 0) | 2577 | if (ret < 0) |
2564 | probeflags &= ~PROBE_RSA; | 2578 | probeflags &= ~PROBE_RSA; |
2565 | 2579 | ||
2580 | if (up->port.iotype != up->cur_iotype) | ||
2581 | set_io_from_upio(port); | ||
2582 | |||
2566 | if (flags & UART_CONFIG_TYPE) | 2583 | if (flags & UART_CONFIG_TYPE) |
2567 | autoconfig(up, probeflags); | 2584 | autoconfig(up, probeflags); |
2568 | if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) | 2585 | if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) |
@@ -2671,6 +2688,11 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) | |||
2671 | { | 2688 | { |
2672 | int i; | 2689 | int i; |
2673 | 2690 | ||
2691 | for (i = 0; i < nr_uarts; i++) { | ||
2692 | struct uart_8250_port *up = &serial8250_ports[i]; | ||
2693 | up->cur_iotype = 0xFF; | ||
2694 | } | ||
2695 | |||
2674 | serial8250_isa_init_ports(); | 2696 | serial8250_isa_init_ports(); |
2675 | 2697 | ||
2676 | for (i = 0; i < nr_uarts; i++) { | 2698 | for (i = 0; i < nr_uarts; i++) { |
diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index 418b4fe9a0a..33149d982e8 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c | |||
@@ -39,9 +39,9 @@ static int __init serial_init_chip(struct parisc_device *dev) | |||
39 | */ | 39 | */ |
40 | if (parisc_parent(dev)->id.hw_type != HPHW_IOA) | 40 | if (parisc_parent(dev)->id.hw_type != HPHW_IOA) |
41 | printk(KERN_INFO | 41 | printk(KERN_INFO |
42 | "Serial: device 0x%lx not configured.\n" | 42 | "Serial: device 0x%llx not configured.\n" |
43 | "Enable support for Wax, Lasi, Asp or Dino.\n", | 43 | "Enable support for Wax, Lasi, Asp or Dino.\n", |
44 | dev->hpa.start); | 44 | (unsigned long long)dev->hpa.start); |
45 | return -ENODEV; | 45 | return -ENODEV; |
46 | } | 46 | } |
47 | 47 | ||
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 938bc1b6c3f..e371a9c1534 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c | |||
@@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = { | |||
2776 | { PCI_VENDOR_ID_OXSEMI, 0x950a, | 2776 | { PCI_VENDOR_ID_OXSEMI, 0x950a, |
2777 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 2777 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
2778 | pbn_b0_2_1130000 }, | 2778 | pbn_b0_2_1130000 }, |
2779 | { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950, | ||
2780 | PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0, | ||
2781 | pbn_b0_1_921600 }, | ||
2779 | { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, | 2782 | { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, |
2780 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 2783 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
2781 | pbn_b0_4_115200 }, | 2784 | pbn_b0_4_115200 }, |
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 343e3a35b6a..1132c5cae7a 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -833,6 +833,7 @@ config SERIAL_IMX | |||
833 | bool "IMX serial port support" | 833 | bool "IMX serial port support" |
834 | depends on ARM && (ARCH_IMX || ARCH_MXC) | 834 | depends on ARM && (ARCH_IMX || ARCH_MXC) |
835 | select SERIAL_CORE | 835 | select SERIAL_CORE |
836 | select RATIONAL | ||
836 | help | 837 | help |
837 | If you have a machine based on a Motorola IMX CPU you | 838 | If you have a machine based on a Motorola IMX CPU you |
838 | can enable its onboard serial port by enabling this option. | 839 | can enable its onboard serial port by enabling this option. |
@@ -860,7 +861,7 @@ config SERIAL_UARTLITE | |||
860 | Say Y here if you want to use the Xilinx uartlite serial controller. | 861 | Say Y here if you want to use the Xilinx uartlite serial controller. |
861 | 862 | ||
862 | To compile this driver as a module, choose M here: the | 863 | To compile this driver as a module, choose M here: the |
863 | module will be called uartlite.ko. | 864 | module will be called uartlite. |
864 | 865 | ||
865 | config SERIAL_UARTLITE_CONSOLE | 866 | config SERIAL_UARTLITE_CONSOLE |
866 | bool "Support for console on Xilinx uartlite serial port" | 867 | bool "Support for console on Xilinx uartlite serial port" |
@@ -1433,4 +1434,11 @@ config SPORT_BAUD_RATE | |||
1433 | default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) | 1434 | default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) |
1434 | default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) | 1435 | default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) |
1435 | 1436 | ||
1437 | config SERIAL_TIMBERDALE | ||
1438 | tristate "Support for timberdale UART" | ||
1439 | depends on MFD_TIMBERDALE | ||
1440 | select SERIAL_CORE | ||
1441 | ---help--- | ||
1442 | Add support for UART controller on timberdale. | ||
1443 | |||
1436 | endmenu | 1444 | endmenu |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d438eb2a73d..45a8658f54d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
@@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o | |||
77 | obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o | 77 | obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o |
78 | obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o | 78 | obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o |
79 | obj-$(CONFIG_SERIAL_QE) += ucc_uart.o | 79 | obj-$(CONFIG_SERIAL_QE) += ucc_uart.o |
80 | obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o | ||
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index e3a5ad5ef1d..58a4879c7e4 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; |
@@ -686,7 +686,7 @@ static int pl010_probe(struct amba_device *dev, void *id) | |||
686 | goto out; | 686 | goto out; |
687 | } | 687 | } |
688 | 688 | ||
689 | base = ioremap(dev->res.start, PAGE_SIZE); | 689 | base = ioremap(dev->res.start, resource_size(&dev->res)); |
690 | if (!base) { | 690 | if (!base) { |
691 | ret = -ENOMEM; | 691 | ret = -ENOMEM; |
692 | goto free; | 692 | goto free; |
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 8b2b9700f3e..bf82e28770a 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 | ||
@@ -750,7 +767,7 @@ static int pl011_probe(struct amba_device *dev, void *id) | |||
750 | goto out; | 767 | goto out; |
751 | } | 768 | } |
752 | 769 | ||
753 | base = ioremap(dev->res.start, PAGE_SIZE); | 770 | base = ioremap(dev->res.start, resource_size(&dev->res)); |
754 | if (!base) { | 771 | if (!base) { |
755 | ret = -ENOMEM; | 772 | ret = -ENOMEM; |
756 | goto free; | 773 | goto free; |
@@ -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/bfin_5xx.c b/drivers/serial/bfin_5xx.c index d86123e0339..e2f6b1bfac9 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) | |||
330 | /* Clear TFI bit */ | 330 | /* Clear TFI bit */ |
331 | UART_PUT_LSR(uart, TFI); | 331 | UART_PUT_LSR(uart, TFI); |
332 | #endif | 332 | #endif |
333 | /* Anomaly notes: | ||
334 | * 05000215 - we always clear ETBEI within last UART TX | ||
335 | * interrupt to end a string. It is always set | ||
336 | * when start a new tx. | ||
337 | */ | ||
333 | UART_CLEAR_IER(uart, ETBEI); | 338 | UART_CLEAR_IER(uart, ETBEI); |
334 | return; | 339 | return; |
335 | } | 340 | } |
@@ -415,6 +420,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) | |||
415 | set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); | 420 | set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); |
416 | set_dma_x_count(uart->tx_dma_channel, uart->tx_count); | 421 | set_dma_x_count(uart->tx_dma_channel, uart->tx_count); |
417 | set_dma_x_modify(uart->tx_dma_channel, 1); | 422 | set_dma_x_modify(uart->tx_dma_channel, 1); |
423 | SSYNC(); | ||
418 | enable_dma(uart->tx_dma_channel); | 424 | enable_dma(uart->tx_dma_channel); |
419 | 425 | ||
420 | UART_SET_IER(uart, ETBEI); | 426 | UART_SET_IER(uart, ETBEI); |
@@ -473,27 +479,41 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) | |||
473 | void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) | 479 | void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) |
474 | { | 480 | { |
475 | int x_pos, pos; | 481 | int x_pos, pos; |
476 | unsigned long flags; | ||
477 | |||
478 | spin_lock_irqsave(&uart->port.lock, flags); | ||
479 | 482 | ||
483 | dma_disable_irq(uart->rx_dma_channel); | ||
484 | spin_lock_bh(&uart->port.lock); | ||
485 | |||
486 | /* 2D DMA RX buffer ring is used. Because curr_y_count and | ||
487 | * curr_x_count can't be read as an atomic operation, | ||
488 | * curr_y_count should be read before curr_x_count. When | ||
489 | * curr_x_count is read, curr_y_count may already indicate | ||
490 | * next buffer line. But, the position calculated here is | ||
491 | * still indicate the old line. The wrong position data may | ||
492 | * be smaller than current buffer tail, which cause garbages | ||
493 | * are received if it is not prohibit. | ||
494 | */ | ||
480 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); | 495 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); |
481 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); | 496 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); |
482 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; | 497 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; |
483 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT) | 498 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) |
484 | uart->rx_dma_nrows = 0; | 499 | uart->rx_dma_nrows = 0; |
485 | x_pos = DMA_RX_XCOUNT - x_pos; | 500 | x_pos = DMA_RX_XCOUNT - x_pos; |
486 | if (x_pos == DMA_RX_XCOUNT) | 501 | if (x_pos == DMA_RX_XCOUNT) |
487 | x_pos = 0; | 502 | x_pos = 0; |
488 | 503 | ||
489 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; | 504 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; |
490 | if (pos != uart->rx_dma_buf.tail) { | 505 | /* Ignore receiving data if new position is in the same line of |
506 | * current buffer tail and small. | ||
507 | */ | ||
508 | if (pos > uart->rx_dma_buf.tail || | ||
509 | uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { | ||
491 | uart->rx_dma_buf.head = pos; | 510 | uart->rx_dma_buf.head = pos; |
492 | bfin_serial_dma_rx_chars(uart); | 511 | bfin_serial_dma_rx_chars(uart); |
493 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; | 512 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; |
494 | } | 513 | } |
495 | 514 | ||
496 | spin_unlock_irqrestore(&uart->port.lock, flags); | 515 | spin_unlock_bh(&uart->port.lock); |
516 | dma_enable_irq(uart->rx_dma_channel); | ||
497 | 517 | ||
498 | mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); | 518 | mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); |
499 | } | 519 | } |
@@ -514,6 +534,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) | |||
514 | if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { | 534 | if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { |
515 | disable_dma(uart->tx_dma_channel); | 535 | disable_dma(uart->tx_dma_channel); |
516 | clear_dma_irqstat(uart->tx_dma_channel); | 536 | clear_dma_irqstat(uart->tx_dma_channel); |
537 | /* Anomaly notes: | ||
538 | * 05000215 - we always clear ETBEI within last UART TX | ||
539 | * interrupt to end a string. It is always set | ||
540 | * when start a new tx. | ||
541 | */ | ||
517 | UART_CLEAR_IER(uart, ETBEI); | 542 | UART_CLEAR_IER(uart, ETBEI); |
518 | xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); | 543 | xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); |
519 | uart->port.icount.tx += uart->tx_count; | 544 | uart->port.icount.tx += uart->tx_count; |
@@ -532,11 +557,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) | |||
532 | { | 557 | { |
533 | struct bfin_serial_port *uart = dev_id; | 558 | struct bfin_serial_port *uart = dev_id; |
534 | unsigned short irqstat; | 559 | unsigned short irqstat; |
560 | int x_pos, pos; | ||
535 | 561 | ||
536 | spin_lock(&uart->port.lock); | 562 | spin_lock(&uart->port.lock); |
537 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); | 563 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); |
538 | clear_dma_irqstat(uart->rx_dma_channel); | 564 | clear_dma_irqstat(uart->rx_dma_channel); |
539 | bfin_serial_dma_rx_chars(uart); | 565 | |
566 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); | ||
567 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); | ||
568 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; | ||
569 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) | ||
570 | uart->rx_dma_nrows = 0; | ||
571 | |||
572 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; | ||
573 | if (pos > uart->rx_dma_buf.tail || | ||
574 | uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { | ||
575 | uart->rx_dma_buf.head = pos; | ||
576 | bfin_serial_dma_rx_chars(uart); | ||
577 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; | ||
578 | } | ||
579 | |||
540 | spin_unlock(&uart->port.lock); | 580 | spin_unlock(&uart->port.lock); |
541 | 581 | ||
542 | return IRQ_HANDLED; | 582 | return IRQ_HANDLED; |
@@ -789,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, | |||
789 | __func__); | 829 | __func__); |
790 | } | 830 | } |
791 | 831 | ||
792 | if (termios->c_cflag & CSTOPB) | 832 | /* Anomaly notes: |
793 | lcr |= STB; | 833 | * 05000231 - STOP bit is always set to 1 whatever the user is set. |
834 | */ | ||
835 | if (termios->c_cflag & CSTOPB) { | ||
836 | if (ANOMALY_05000231) | ||
837 | printk(KERN_WARNING "STOP bits other than 1 is not " | ||
838 | "supported in case of anomaly 05000231.\n"); | ||
839 | else | ||
840 | lcr |= STB; | ||
841 | } | ||
794 | if (termios->c_cflag & PARENB) | 842 | if (termios->c_cflag & PARENB) |
795 | lcr |= PEN; | 843 | lcr |= PEN; |
796 | if (!(termios->c_cflag & PARODD)) | 844 | if (!(termios->c_cflag & PARODD)) |
@@ -940,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port) | |||
940 | } | 988 | } |
941 | 989 | ||
942 | #ifdef CONFIG_CONSOLE_POLL | 990 | #ifdef CONFIG_CONSOLE_POLL |
991 | /* Anomaly notes: | ||
992 | * 05000099 - Because we only use THRE in poll_put and DR in poll_get, | ||
993 | * losing other bits of UART_LSR is not a problem here. | ||
994 | */ | ||
943 | static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) | 995 | static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) |
944 | { | 996 | { |
945 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; | 997 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; |
@@ -1245,12 +1297,17 @@ static __init void early_serial_write(struct console *con, const char *s, | |||
1245 | } | 1297 | } |
1246 | } | 1298 | } |
1247 | 1299 | ||
1300 | /* | ||
1301 | * This should have a .setup or .early_setup in it, but then things get called | ||
1302 | * without the command line options, and the baud rate gets messed up - so | ||
1303 | * don't let the common infrastructure play with things. (see calls to setup | ||
1304 | * & earlysetup in ./kernel/printk.c:register_console() | ||
1305 | */ | ||
1248 | static struct __initdata console bfin_early_serial_console = { | 1306 | static struct __initdata console bfin_early_serial_console = { |
1249 | .name = "early_BFuart", | 1307 | .name = "early_BFuart", |
1250 | .write = early_serial_write, | 1308 | .write = early_serial_write, |
1251 | .device = uart_console_device, | 1309 | .device = uart_console_device, |
1252 | .flags = CON_PRINTBUFFER, | 1310 | .flags = CON_PRINTBUFFER, |
1253 | .setup = bfin_serial_console_setup, | ||
1254 | .index = -1, | 1311 | .index = -1, |
1255 | .data = &bfin_serial_reg, | 1312 | .data = &bfin_serial_reg, |
1256 | }; | 1313 | }; |
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index 529c0ff7952..34b4ae0fe76 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c | |||
@@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) | |||
101 | { | 101 | { |
102 | pr_debug("%s value:%x\n", __func__, value); | 102 | pr_debug("%s value:%x\n", __func__, value); |
103 | /* Place a Start and Stop bit */ | 103 | /* Place a Start and Stop bit */ |
104 | __asm__ volatile ( | 104 | __asm__ __volatile__ ( |
105 | "R2 = b#01111111100;\n\t" | 105 | "R2 = b#01111111100;" |
106 | "R3 = b#10000000001;\n\t" | 106 | "R3 = b#10000000001;" |
107 | "%0 <<= 2;\n\t" | 107 | "%0 <<= 2;" |
108 | "%0 = %0 & R2;\n\t" | 108 | "%0 = %0 & R2;" |
109 | "%0 = %0 | R3;\n\t" | 109 | "%0 = %0 | R3;" |
110 | :"=r"(value) | 110 | : "=d"(value) |
111 | :"0"(value) | 111 | : "d"(value) |
112 | :"R2", "R3"); | 112 | : "ASTAT", "R2", "R3" |
113 | ); | ||
113 | pr_debug("%s value:%x\n", __func__, value); | 114 | pr_debug("%s value:%x\n", __func__, value); |
114 | 115 | ||
115 | SPORT_PUT_TX(up, value); | 116 | SPORT_PUT_TX(up, value); |
@@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) | |||
118 | static inline unsigned int rx_one_byte(struct sport_uart_port *up) | 119 | static inline unsigned int rx_one_byte(struct sport_uart_port *up) |
119 | { | 120 | { |
120 | unsigned int value, extract; | 121 | unsigned int value, extract; |
122 | u32 tmp_mask1, tmp_mask2, tmp_shift, tmp; | ||
121 | 123 | ||
122 | value = SPORT_GET_RX32(up); | 124 | value = SPORT_GET_RX32(up); |
123 | pr_debug("%s value:%x\n", __func__, value); | 125 | pr_debug("%s value:%x\n", __func__, value); |
124 | 126 | ||
125 | /* Extract 8 bits data */ | 127 | /* Extract 8 bits data */ |
126 | __asm__ volatile ( | 128 | __asm__ __volatile__ ( |
127 | "R5 = 0;\n\t" | 129 | "%[extr] = 0;" |
128 | "P0 = 8;\n\t" | 130 | "%[mask1] = 0x1801(Z);" |
129 | "R1 = 0x1801(Z);\n\t" | 131 | "%[mask2] = 0x0300(Z);" |
130 | "R3 = 0x0300(Z);\n\t" | 132 | "%[shift] = 0;" |
131 | "R4 = 0;\n\t" | 133 | "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];" |
132 | "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t" | 134 | ".Lloop_s:" |
133 | "R2 = extract(%1, R1.L)(Z);\n\t" | 135 | "%[tmp] = extract(%[val], %[mask1].L)(Z);" |
134 | "R2 <<= R4;\n\t" | 136 | "%[tmp] <<= %[shift];" |
135 | "R5 = R5 | R2;\n\t" | 137 | "%[extr] = %[extr] | %[tmp];" |
136 | "R1 = R1 - R3;\nloop_e:\t" | 138 | "%[mask1] = %[mask1] - %[mask2];" |
137 | "R4 += 1;\n\t" | 139 | ".Lloop_e:" |
138 | "%0 = R5;\n\t" | 140 | "%[shift] += 1;" |
139 | :"=r"(extract) | 141 | : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp), |
140 | :"r"(value) | 142 | [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2) |
141 | :"P0", "R1", "R2","R3","R4", "R5"); | 143 | : "d"(value), [lc]"a"(8) |
144 | : "ASTAT", "LB0", "LC0", "LT0" | ||
145 | ); | ||
142 | 146 | ||
143 | pr_debug(" extract:%x\n", extract); | 147 | pr_debug(" extract:%x\n", extract); |
144 | return extract; | 148 | return extract; |
@@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) | |||
149 | int tclkdiv, tfsdiv, rclkdiv; | 153 | int tclkdiv, tfsdiv, rclkdiv; |
150 | 154 | ||
151 | /* Set TCR1 and TCR2 */ | 155 | /* Set TCR1 and TCR2 */ |
152 | SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK)); | 156 | SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); |
153 | SPORT_PUT_TCR2(up, 10); | 157 | SPORT_PUT_TCR2(up, 10); |
154 | pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); | 158 | pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); |
155 | 159 | ||
@@ -419,7 +423,7 @@ static void sport_shutdown(struct uart_port *port) | |||
419 | } | 423 | } |
420 | 424 | ||
421 | static void sport_set_termios(struct uart_port *port, | 425 | static void sport_set_termios(struct uart_port *port, |
422 | struct termios *termios, struct termios *old) | 426 | struct ktermios *termios, struct ktermios *old) |
423 | { | 427 | { |
424 | pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); | 428 | pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); |
425 | uart_update_timeout(port, CS8 ,port->uartclk); | 429 | uart_update_timeout(port, CS8 ,port->uartclk); |
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 6579e2be1dd..9f2891c2c4a 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c | |||
@@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head); | |||
137 | static spinlock_t icom_lock; | 137 | static spinlock_t icom_lock; |
138 | 138 | ||
139 | #ifdef ICOM_TRACE | 139 | #ifdef ICOM_TRACE |
140 | static inline void trace(struct icom_port *, char *, unsigned long) {}; | 140 | static inline void trace(struct icom_port *icom_port, char *trace_pt, |
141 | unsigned long trace_data) | ||
142 | { | ||
143 | dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", | ||
144 | icom_port->port, trace_pt, trace_data); | ||
145 | } | ||
141 | #else | 146 | #else |
142 | static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; | 147 | static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; |
143 | #endif | 148 | #endif |
@@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port) | |||
408 | release_firmware(fw); | 413 | release_firmware(fw); |
409 | 414 | ||
410 | /* Set Hardware level */ | 415 | /* Set Hardware level */ |
411 | if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2) | 416 | if (icom_port->adapter->version == ADAPTER_V2) |
412 | writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); | 417 | writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); |
413 | 418 | ||
414 | /* Start the processor in Adapter */ | 419 | /* Start the processor in Adapter */ |
@@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id) | |||
861 | /* find icom_port for this interrupt */ | 866 | /* find icom_port for this interrupt */ |
862 | icom_adapter = (struct icom_adapter *) dev_id; | 867 | icom_adapter = (struct icom_adapter *) dev_id; |
863 | 868 | ||
864 | if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { | 869 | if (icom_adapter->version == ADAPTER_V2) { |
865 | int_reg = icom_adapter->base_addr + 0x8024; | 870 | int_reg = icom_adapter->base_addr + 0x8024; |
866 | 871 | ||
867 | adapter_interrupts = readl(int_reg); | 872 | adapter_interrupts = readl(int_reg); |
@@ -1472,8 +1477,8 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) | |||
1472 | 1477 | ||
1473 | free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); | 1478 | free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); |
1474 | iounmap(icom_adapter->base_addr); | 1479 | iounmap(icom_adapter->base_addr); |
1475 | icom_free_adapter(icom_adapter); | ||
1476 | pci_release_regions(icom_adapter->pci_dev); | 1480 | pci_release_regions(icom_adapter->pci_dev); |
1481 | icom_free_adapter(icom_adapter); | ||
1477 | } | 1482 | } |
1478 | 1483 | ||
1479 | static void icom_kref_release(struct kref *kref) | 1484 | static void icom_kref_release(struct kref *kref) |
@@ -1647,15 +1652,6 @@ static void __exit icom_exit(void) | |||
1647 | module_init(icom_init); | 1652 | module_init(icom_init); |
1648 | module_exit(icom_exit); | 1653 | module_exit(icom_exit); |
1649 | 1654 | ||
1650 | #ifdef ICOM_TRACE | ||
1651 | static inline void trace(struct icom_port *icom_port, char *trace_pt, | ||
1652 | unsigned long trace_data) | ||
1653 | { | ||
1654 | dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", | ||
1655 | icom_port->port, trace_pt, trace_data); | ||
1656 | } | ||
1657 | #endif | ||
1658 | |||
1659 | MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>"); | 1655 | MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>"); |
1660 | MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); | 1656 | MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); |
1661 | MODULE_SUPPORTED_DEVICE | 1657 | MODULE_SUPPORTED_DEVICE |
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 9f460b175c5..285b414f305 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 | }; |
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index c0a3e2734e2..4e5f3bde046 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h | |||
@@ -61,6 +61,7 @@ enum { | |||
61 | if ((DBG_##nlevel & jsm_debug)) \ | 61 | if ((DBG_##nlevel & jsm_debug)) \ |
62 | dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) | 62 | dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) |
63 | 63 | ||
64 | #define MAXLINES 256 | ||
64 | #define MAXPORTS 8 | 65 | #define MAXPORTS 8 |
65 | #define MAX_STOPS_SENT 5 | 66 | #define MAX_STOPS_SENT 5 |
66 | 67 | ||
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 31496dc0a0d..107ce2e187b 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c | |||
@@ -33,6 +33,8 @@ | |||
33 | 33 | ||
34 | #include "jsm.h" | 34 | #include "jsm.h" |
35 | 35 | ||
36 | static DECLARE_BITMAP(linemap, MAXLINES); | ||
37 | |||
36 | static void jsm_carrier(struct jsm_channel *ch); | 38 | static void jsm_carrier(struct jsm_channel *ch); |
37 | 39 | ||
38 | static inline int jsm_get_mstat(struct jsm_channel *ch) | 40 | static inline int jsm_get_mstat(struct jsm_channel *ch) |
@@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd) | |||
433 | int __devinit jsm_uart_port_init(struct jsm_board *brd) | 435 | int __devinit jsm_uart_port_init(struct jsm_board *brd) |
434 | { | 436 | { |
435 | int i; | 437 | int i; |
438 | unsigned int line; | ||
436 | struct jsm_channel *ch; | 439 | struct jsm_channel *ch; |
437 | 440 | ||
438 | if (!brd) | 441 | if (!brd) |
@@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd) | |||
459 | brd->channels[i]->uart_port.membase = brd->re_map_membase; | 462 | brd->channels[i]->uart_port.membase = brd->re_map_membase; |
460 | brd->channels[i]->uart_port.fifosize = 16; | 463 | brd->channels[i]->uart_port.fifosize = 16; |
461 | brd->channels[i]->uart_port.ops = &jsm_ops; | 464 | brd->channels[i]->uart_port.ops = &jsm_ops; |
462 | brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2; | 465 | line = find_first_zero_bit(linemap, MAXLINES); |
466 | if (line >= MAXLINES) { | ||
467 | printk(KERN_INFO "jsm: linemap is full, added device failed\n"); | ||
468 | continue; | ||
469 | } else | ||
470 | set_bit((int)line, linemap); | ||
471 | brd->channels[i]->uart_port.line = line; | ||
463 | if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) | 472 | if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) |
464 | printk(KERN_INFO "Added device failed\n"); | 473 | printk(KERN_INFO "jsm: add device failed\n"); |
465 | else | 474 | else |
466 | printk(KERN_INFO "Added device \n"); | 475 | printk(KERN_INFO "Added device \n"); |
467 | } | 476 | } |
@@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd) | |||
494 | 503 | ||
495 | ch = brd->channels[i]; | 504 | ch = brd->channels[i]; |
496 | 505 | ||
506 | clear_bit((int)(ch->uart_port.line), linemap); | ||
497 | uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); | 507 | uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); |
498 | } | 508 | } |
499 | 509 | ||
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 7f72f8ceaa6..b3feb6198d5 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c | |||
@@ -988,7 +988,7 @@ mpc52xx_console_setup(struct console *co, char *options) | |||
988 | pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n", | 988 | pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n", |
989 | co, co->index, options); | 989 | co, co->index, options); |
990 | 990 | ||
991 | if ((co->index < 0) || (co->index > MPC52xx_PSC_MAXNUM)) { | 991 | if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) { |
992 | pr_debug("PSC%x out of range\n", co->index); | 992 | pr_debug("PSC%x out of range\n", co->index); |
993 | return -EINVAL; | 993 | return -EINVAL; |
994 | } | 994 | } |
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index dbf5357a77b..a4cf1079b31 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c | |||
@@ -47,12 +47,17 @@ | |||
47 | #include <linux/clk.h> | 47 | #include <linux/clk.h> |
48 | #include <linux/ctype.h> | 48 | #include <linux/ctype.h> |
49 | #include <linux/err.h> | 49 | #include <linux/err.h> |
50 | #include <linux/list.h> | ||
50 | 51 | ||
51 | #ifdef CONFIG_SUPERH | 52 | #ifdef CONFIG_SUPERH |
52 | #include <asm/clock.h> | 53 | #include <asm/clock.h> |
53 | #include <asm/sh_bios.h> | 54 | #include <asm/sh_bios.h> |
54 | #endif | 55 | #endif |
55 | 56 | ||
57 | #ifdef CONFIG_H8300 | ||
58 | #include <asm/gpio.h> | ||
59 | #endif | ||
60 | |||
56 | #include "sh-sci.h" | 61 | #include "sh-sci.h" |
57 | 62 | ||
58 | struct sci_port { | 63 | struct sci_port { |
@@ -75,14 +80,22 @@ struct sci_port { | |||
75 | int break_flag; | 80 | int break_flag; |
76 | 81 | ||
77 | #ifdef CONFIG_HAVE_CLK | 82 | #ifdef CONFIG_HAVE_CLK |
78 | /* Port clock */ | 83 | /* Interface clock */ |
79 | struct clk *clk; | 84 | struct clk *iclk; |
85 | /* Data clock */ | ||
86 | struct clk *dclk; | ||
80 | #endif | 87 | #endif |
88 | struct list_head node; | ||
81 | }; | 89 | }; |
82 | 90 | ||
83 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE | 91 | struct sh_sci_priv { |
84 | static struct sci_port *serial_console_port; | 92 | spinlock_t lock; |
93 | struct list_head ports; | ||
94 | |||
95 | #ifdef CONFIG_HAVE_CLK | ||
96 | struct notifier_block clk_nb; | ||
85 | #endif | 97 | #endif |
98 | }; | ||
86 | 99 | ||
87 | /* Function prototypes */ | 100 | /* Function prototypes */ |
88 | static void sci_stop_tx(struct uart_port *port); | 101 | static void sci_stop_tx(struct uart_port *port); |
@@ -138,9 +151,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) | |||
138 | status = sci_in(port, SCxSR); | 151 | status = sci_in(port, SCxSR); |
139 | } while (!(status & SCxSR_TDxE(port))); | 152 | } while (!(status & SCxSR_TDxE(port))); |
140 | 153 | ||
141 | sci_in(port, SCxSR); /* Dummy read */ | ||
142 | sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); | ||
143 | sci_out(port, SCxTDR, c); | 154 | sci_out(port, SCxTDR, c); |
155 | sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); | ||
144 | } | 156 | } |
145 | #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ | 157 | #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ |
146 | 158 | ||
@@ -159,12 +171,12 @@ static void h8300_sci_config(struct uart_port *port, unsigned int ctrl) | |||
159 | *mstpcrl &= ~mask; | 171 | *mstpcrl &= ~mask; |
160 | } | 172 | } |
161 | 173 | ||
162 | static inline void h8300_sci_enable(struct uart_port *port) | 174 | static void h8300_sci_enable(struct uart_port *port) |
163 | { | 175 | { |
164 | h8300_sci_config(port, sci_enable); | 176 | h8300_sci_config(port, sci_enable); |
165 | } | 177 | } |
166 | 178 | ||
167 | static inline void h8300_sci_disable(struct uart_port *port) | 179 | static void h8300_sci_disable(struct uart_port *port) |
168 | { | 180 | { |
169 | h8300_sci_config(port, sci_disable); | 181 | h8300_sci_config(port, sci_disable); |
170 | } | 182 | } |
@@ -611,7 +623,7 @@ static inline int sci_handle_breaks(struct uart_port *port) | |||
611 | int copied = 0; | 623 | int copied = 0; |
612 | unsigned short status = sci_in(port, SCxSR); | 624 | unsigned short status = sci_in(port, SCxSR); |
613 | struct tty_struct *tty = port->info->port.tty; | 625 | struct tty_struct *tty = port->info->port.tty; |
614 | struct sci_port *s = &sci_ports[port->line]; | 626 | struct sci_port *s = to_sci_port(port); |
615 | 627 | ||
616 | if (uart_handle_break(port)) | 628 | if (uart_handle_break(port)) |
617 | return 0; | 629 | return 0; |
@@ -726,19 +738,43 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) | |||
726 | static int sci_notifier(struct notifier_block *self, | 738 | static int sci_notifier(struct notifier_block *self, |
727 | unsigned long phase, void *p) | 739 | unsigned long phase, void *p) |
728 | { | 740 | { |
729 | int i; | 741 | struct sh_sci_priv *priv = container_of(self, |
742 | struct sh_sci_priv, clk_nb); | ||
743 | struct sci_port *sci_port; | ||
744 | unsigned long flags; | ||
730 | 745 | ||
731 | if ((phase == CPUFREQ_POSTCHANGE) || | 746 | if ((phase == CPUFREQ_POSTCHANGE) || |
732 | (phase == CPUFREQ_RESUMECHANGE)) | 747 | (phase == CPUFREQ_RESUMECHANGE)) { |
733 | for (i = 0; i < SCI_NPORTS; i++) { | 748 | spin_lock_irqsave(&priv->lock, flags); |
734 | struct sci_port *s = &sci_ports[i]; | 749 | list_for_each_entry(sci_port, &priv->ports, node) |
735 | s->port.uartclk = clk_get_rate(s->clk); | 750 | sci_port->port.uartclk = clk_get_rate(sci_port->dclk); |
736 | } | 751 | |
752 | spin_unlock_irqrestore(&priv->lock, flags); | ||
753 | } | ||
737 | 754 | ||
738 | return NOTIFY_OK; | 755 | return NOTIFY_OK; |
739 | } | 756 | } |
740 | 757 | ||
741 | static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; | 758 | static void sci_clk_enable(struct uart_port *port) |
759 | { | ||
760 | struct sci_port *sci_port = to_sci_port(port); | ||
761 | |||
762 | clk_enable(sci_port->dclk); | ||
763 | sci_port->port.uartclk = clk_get_rate(sci_port->dclk); | ||
764 | |||
765 | if (sci_port->iclk) | ||
766 | clk_enable(sci_port->iclk); | ||
767 | } | ||
768 | |||
769 | static void sci_clk_disable(struct uart_port *port) | ||
770 | { | ||
771 | struct sci_port *sci_port = to_sci_port(port); | ||
772 | |||
773 | if (sci_port->iclk) | ||
774 | clk_disable(sci_port->iclk); | ||
775 | |||
776 | clk_disable(sci_port->dclk); | ||
777 | } | ||
742 | #endif | 778 | #endif |
743 | 779 | ||
744 | static int sci_request_irq(struct sci_port *port) | 780 | static int sci_request_irq(struct sci_port *port) |
@@ -865,15 +901,11 @@ static void sci_break_ctl(struct uart_port *port, int break_state) | |||
865 | 901 | ||
866 | static int sci_startup(struct uart_port *port) | 902 | static int sci_startup(struct uart_port *port) |
867 | { | 903 | { |
868 | struct sci_port *s = &sci_ports[port->line]; | 904 | struct sci_port *s = to_sci_port(port); |
869 | 905 | ||
870 | if (s->enable) | 906 | if (s->enable) |
871 | s->enable(port); | 907 | s->enable(port); |
872 | 908 | ||
873 | #ifdef CONFIG_HAVE_CLK | ||
874 | s->clk = clk_get(NULL, "module_clk"); | ||
875 | #endif | ||
876 | |||
877 | sci_request_irq(s); | 909 | sci_request_irq(s); |
878 | sci_start_tx(port); | 910 | sci_start_tx(port); |
879 | sci_start_rx(port, 1); | 911 | sci_start_rx(port, 1); |
@@ -883,7 +915,7 @@ static int sci_startup(struct uart_port *port) | |||
883 | 915 | ||
884 | static void sci_shutdown(struct uart_port *port) | 916 | static void sci_shutdown(struct uart_port *port) |
885 | { | 917 | { |
886 | struct sci_port *s = &sci_ports[port->line]; | 918 | struct sci_port *s = to_sci_port(port); |
887 | 919 | ||
888 | sci_stop_rx(port); | 920 | sci_stop_rx(port); |
889 | sci_stop_tx(port); | 921 | sci_stop_tx(port); |
@@ -891,11 +923,6 @@ static void sci_shutdown(struct uart_port *port) | |||
891 | 923 | ||
892 | if (s->disable) | 924 | if (s->disable) |
893 | s->disable(port); | 925 | s->disable(port); |
894 | |||
895 | #ifdef CONFIG_HAVE_CLK | ||
896 | clk_put(s->clk); | ||
897 | s->clk = NULL; | ||
898 | #endif | ||
899 | } | 926 | } |
900 | 927 | ||
901 | static void sci_set_termios(struct uart_port *port, struct ktermios *termios, | 928 | static void sci_set_termios(struct uart_port *port, struct ktermios *termios, |
@@ -980,25 +1007,31 @@ static int sci_request_port(struct uart_port *port) | |||
980 | 1007 | ||
981 | static void sci_config_port(struct uart_port *port, int flags) | 1008 | static void sci_config_port(struct uart_port *port, int flags) |
982 | { | 1009 | { |
983 | struct sci_port *s = &sci_ports[port->line]; | 1010 | struct sci_port *s = to_sci_port(port); |
984 | 1011 | ||
985 | port->type = s->type; | 1012 | port->type = s->type; |
986 | 1013 | ||
987 | if (port->flags & UPF_IOREMAP && !port->membase) { | 1014 | if (port->membase) |
988 | #if defined(CONFIG_SUPERH64) | 1015 | return; |
989 | port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); | 1016 | |
990 | port->membase = (void __iomem *)port->mapbase; | 1017 | if (port->flags & UPF_IOREMAP) { |
991 | #else | ||
992 | port->membase = ioremap_nocache(port->mapbase, 0x40); | 1018 | port->membase = ioremap_nocache(port->mapbase, 0x40); |
993 | #endif | ||
994 | 1019 | ||
995 | dev_err(port->dev, "can't remap port#%d\n", port->line); | 1020 | if (IS_ERR(port->membase)) |
1021 | dev_err(port->dev, "can't remap port#%d\n", port->line); | ||
1022 | } else { | ||
1023 | /* | ||
1024 | * For the simple (and majority of) cases where we don't | ||
1025 | * need to do any remapping, just cast the cookie | ||
1026 | * directly. | ||
1027 | */ | ||
1028 | port->membase = (void __iomem *)port->mapbase; | ||
996 | } | 1029 | } |
997 | } | 1030 | } |
998 | 1031 | ||
999 | static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) | 1032 | static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) |
1000 | { | 1033 | { |
1001 | struct sci_port *s = &sci_ports[port->line]; | 1034 | struct sci_port *s = to_sci_port(port); |
1002 | 1035 | ||
1003 | if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) | 1036 | if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) |
1004 | return -EINVAL; | 1037 | return -EINVAL; |
@@ -1032,63 +1065,60 @@ static struct uart_ops sci_uart_ops = { | |||
1032 | #endif | 1065 | #endif |
1033 | }; | 1066 | }; |
1034 | 1067 | ||
1035 | static void __init sci_init_ports(void) | 1068 | static void __devinit sci_init_single(struct platform_device *dev, |
1069 | struct sci_port *sci_port, | ||
1070 | unsigned int index, | ||
1071 | struct plat_sci_port *p) | ||
1036 | { | 1072 | { |
1037 | static int first = 1; | 1073 | sci_port->port.ops = &sci_uart_ops; |
1038 | int i; | 1074 | sci_port->port.iotype = UPIO_MEM; |
1039 | 1075 | sci_port->port.line = index; | |
1040 | if (!first) | 1076 | sci_port->port.fifosize = 1; |
1041 | return; | ||
1042 | |||
1043 | first = 0; | ||
1044 | |||
1045 | for (i = 0; i < SCI_NPORTS; i++) { | ||
1046 | sci_ports[i].port.ops = &sci_uart_ops; | ||
1047 | sci_ports[i].port.iotype = UPIO_MEM; | ||
1048 | sci_ports[i].port.line = i; | ||
1049 | sci_ports[i].port.fifosize = 1; | ||
1050 | 1077 | ||
1051 | #if defined(__H8300H__) || defined(__H8300S__) | 1078 | #if defined(__H8300H__) || defined(__H8300S__) |
1052 | #ifdef __H8300S__ | 1079 | #ifdef __H8300S__ |
1053 | sci_ports[i].enable = h8300_sci_enable; | 1080 | sci_port->enable = h8300_sci_enable; |
1054 | sci_ports[i].disable = h8300_sci_disable; | 1081 | sci_port->disable = h8300_sci_disable; |
1055 | #endif | 1082 | #endif |
1056 | sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK; | 1083 | sci_port->port.uartclk = CONFIG_CPU_CLOCK; |
1057 | #elif defined(CONFIG_HAVE_CLK) | 1084 | #elif defined(CONFIG_HAVE_CLK) |
1058 | /* | 1085 | sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL; |
1059 | * XXX: We should use a proper SCI/SCIF clock | 1086 | sci_port->dclk = clk_get(&dev->dev, "peripheral_clk"); |
1060 | */ | 1087 | sci_port->enable = sci_clk_enable; |
1061 | { | 1088 | sci_port->disable = sci_clk_disable; |
1062 | struct clk *clk = clk_get(NULL, "module_clk"); | ||
1063 | sci_ports[i].port.uartclk = clk_get_rate(clk); | ||
1064 | clk_put(clk); | ||
1065 | } | ||
1066 | #else | 1089 | #else |
1067 | #error "Need a valid uartclk" | 1090 | #error "Need a valid uartclk" |
1068 | #endif | 1091 | #endif |
1069 | 1092 | ||
1070 | sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i]; | 1093 | sci_port->break_timer.data = (unsigned long)sci_port; |
1071 | sci_ports[i].break_timer.function = sci_break_timer; | 1094 | sci_port->break_timer.function = sci_break_timer; |
1095 | init_timer(&sci_port->break_timer); | ||
1072 | 1096 | ||
1073 | init_timer(&sci_ports[i].break_timer); | 1097 | sci_port->port.mapbase = p->mapbase; |
1074 | } | 1098 | sci_port->port.membase = p->membase; |
1075 | } | ||
1076 | |||
1077 | int __init early_sci_setup(struct uart_port *port) | ||
1078 | { | ||
1079 | if (unlikely(port->line > SCI_NPORTS)) | ||
1080 | return -ENODEV; | ||
1081 | 1099 | ||
1082 | sci_init_ports(); | 1100 | sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; |
1101 | sci_port->port.flags = p->flags; | ||
1102 | sci_port->port.dev = &dev->dev; | ||
1103 | sci_port->type = sci_port->port.type = p->type; | ||
1083 | 1104 | ||
1084 | sci_ports[port->line].port.membase = port->membase; | 1105 | memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); |
1085 | sci_ports[port->line].port.mapbase = port->mapbase; | ||
1086 | sci_ports[port->line].port.type = port->type; | ||
1087 | 1106 | ||
1088 | return 0; | ||
1089 | } | 1107 | } |
1090 | 1108 | ||
1091 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE | 1109 | #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE |
1110 | static struct tty_driver *serial_console_device(struct console *co, int *index) | ||
1111 | { | ||
1112 | struct uart_driver *p = &sci_uart_driver; | ||
1113 | *index = co->index; | ||
1114 | return p->tty_driver; | ||
1115 | } | ||
1116 | |||
1117 | static void serial_console_putchar(struct uart_port *port, int ch) | ||
1118 | { | ||
1119 | sci_poll_put_char(port, ch); | ||
1120 | } | ||
1121 | |||
1092 | /* | 1122 | /* |
1093 | * Print a string to the serial port trying not to disturb | 1123 | * Print a string to the serial port trying not to disturb |
1094 | * any possible real use of the port... | 1124 | * any possible real use of the port... |
@@ -1096,25 +1126,27 @@ int __init early_sci_setup(struct uart_port *port) | |||
1096 | static void serial_console_write(struct console *co, const char *s, | 1126 | static void serial_console_write(struct console *co, const char *s, |
1097 | unsigned count) | 1127 | unsigned count) |
1098 | { | 1128 | { |
1099 | struct uart_port *port = &serial_console_port->port; | 1129 | struct uart_port *port = co->data; |
1130 | struct sci_port *sci_port = to_sci_port(port); | ||
1100 | unsigned short bits; | 1131 | unsigned short bits; |
1101 | int i; | ||
1102 | 1132 | ||
1103 | for (i = 0; i < count; i++) { | 1133 | if (sci_port->enable) |
1104 | if (*s == 10) | 1134 | sci_port->enable(port); |
1105 | sci_poll_put_char(port, '\r'); | ||
1106 | 1135 | ||
1107 | sci_poll_put_char(port, *s++); | 1136 | uart_console_write(port, s, count, serial_console_putchar); |
1108 | } | ||
1109 | 1137 | ||
1110 | /* wait until fifo is empty and last bit has been transmitted */ | 1138 | /* wait until fifo is empty and last bit has been transmitted */ |
1111 | bits = SCxSR_TDxE(port) | SCxSR_TEND(port); | 1139 | bits = SCxSR_TDxE(port) | SCxSR_TEND(port); |
1112 | while ((sci_in(port, SCxSR) & bits) != bits) | 1140 | while ((sci_in(port, SCxSR) & bits) != bits) |
1113 | cpu_relax(); | 1141 | cpu_relax(); |
1142 | |||
1143 | if (sci_port->disable); | ||
1144 | sci_port->disable(port); | ||
1114 | } | 1145 | } |
1115 | 1146 | ||
1116 | static int __init serial_console_setup(struct console *co, char *options) | 1147 | static int __init serial_console_setup(struct console *co, char *options) |
1117 | { | 1148 | { |
1149 | struct sci_port *sci_port; | ||
1118 | struct uart_port *port; | 1150 | struct uart_port *port; |
1119 | int baud = 115200; | 1151 | int baud = 115200; |
1120 | int bits = 8; | 1152 | int bits = 8; |
@@ -1130,8 +1162,9 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1130 | if (co->index >= SCI_NPORTS) | 1162 | if (co->index >= SCI_NPORTS) |
1131 | co->index = 0; | 1163 | co->index = 0; |
1132 | 1164 | ||
1133 | serial_console_port = &sci_ports[co->index]; | 1165 | sci_port = &sci_ports[co->index]; |
1134 | port = &serial_console_port->port; | 1166 | port = &sci_port->port; |
1167 | co->data = port; | ||
1135 | 1168 | ||
1136 | /* | 1169 | /* |
1137 | * Also need to check port->type, we don't actually have any | 1170 | * Also need to check port->type, we don't actually have any |
@@ -1141,21 +1174,11 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1141 | */ | 1174 | */ |
1142 | if (!port->type) | 1175 | if (!port->type) |
1143 | return -ENODEV; | 1176 | return -ENODEV; |
1144 | if (!port->membase || !port->mapbase) | ||
1145 | return -ENODEV; | ||
1146 | |||
1147 | port->type = serial_console_port->type; | ||
1148 | |||
1149 | #ifdef CONFIG_HAVE_CLK | ||
1150 | if (!serial_console_port->clk) | ||
1151 | serial_console_port->clk = clk_get(NULL, "module_clk"); | ||
1152 | #endif | ||
1153 | 1177 | ||
1154 | if (port->flags & UPF_IOREMAP) | 1178 | sci_config_port(port, 0); |
1155 | sci_config_port(port, 0); | ||
1156 | 1179 | ||
1157 | if (serial_console_port->enable) | 1180 | if (sci_port->enable) |
1158 | serial_console_port->enable(port); | 1181 | sci_port->enable(port); |
1159 | 1182 | ||
1160 | if (options) | 1183 | if (options) |
1161 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 1184 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
@@ -1166,22 +1189,21 @@ static int __init serial_console_setup(struct console *co, char *options) | |||
1166 | if (ret == 0) | 1189 | if (ret == 0) |
1167 | sci_stop_rx(port); | 1190 | sci_stop_rx(port); |
1168 | #endif | 1191 | #endif |
1192 | /* TODO: disable clock */ | ||
1169 | return ret; | 1193 | return ret; |
1170 | } | 1194 | } |
1171 | 1195 | ||
1172 | static struct console serial_console = { | 1196 | static struct console serial_console = { |
1173 | .name = "ttySC", | 1197 | .name = "ttySC", |
1174 | .device = uart_console_device, | 1198 | .device = serial_console_device, |
1175 | .write = serial_console_write, | 1199 | .write = serial_console_write, |
1176 | .setup = serial_console_setup, | 1200 | .setup = serial_console_setup, |
1177 | .flags = CON_PRINTBUFFER, | 1201 | .flags = CON_PRINTBUFFER, |
1178 | .index = -1, | 1202 | .index = -1, |
1179 | .data = &sci_uart_driver, | ||
1180 | }; | 1203 | }; |
1181 | 1204 | ||
1182 | static int __init sci_console_init(void) | 1205 | static int __init sci_console_init(void) |
1183 | { | 1206 | { |
1184 | sci_init_ports(); | ||
1185 | register_console(&serial_console); | 1207 | register_console(&serial_console); |
1186 | return 0; | 1208 | return 0; |
1187 | } | 1209 | } |
@@ -1207,6 +1229,61 @@ static struct uart_driver sci_uart_driver = { | |||
1207 | .cons = SCI_CONSOLE, | 1229 | .cons = SCI_CONSOLE, |
1208 | }; | 1230 | }; |
1209 | 1231 | ||
1232 | |||
1233 | static int sci_remove(struct platform_device *dev) | ||
1234 | { | ||
1235 | struct sh_sci_priv *priv = platform_get_drvdata(dev); | ||
1236 | struct sci_port *p; | ||
1237 | unsigned long flags; | ||
1238 | |||
1239 | #ifdef CONFIG_HAVE_CLK | ||
1240 | cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1241 | #endif | ||
1242 | |||
1243 | spin_lock_irqsave(&priv->lock, flags); | ||
1244 | list_for_each_entry(p, &priv->ports, node) | ||
1245 | uart_remove_one_port(&sci_uart_driver, &p->port); | ||
1246 | |||
1247 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1248 | |||
1249 | kfree(priv); | ||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1253 | static int __devinit sci_probe_single(struct platform_device *dev, | ||
1254 | unsigned int index, | ||
1255 | struct plat_sci_port *p, | ||
1256 | struct sci_port *sciport) | ||
1257 | { | ||
1258 | struct sh_sci_priv *priv = platform_get_drvdata(dev); | ||
1259 | unsigned long flags; | ||
1260 | int ret; | ||
1261 | |||
1262 | /* Sanity check */ | ||
1263 | if (unlikely(index >= SCI_NPORTS)) { | ||
1264 | dev_notice(&dev->dev, "Attempting to register port " | ||
1265 | "%d when only %d are available.\n", | ||
1266 | index+1, SCI_NPORTS); | ||
1267 | dev_notice(&dev->dev, "Consider bumping " | ||
1268 | "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); | ||
1269 | return 0; | ||
1270 | } | ||
1271 | |||
1272 | sci_init_single(dev, sciport, index, p); | ||
1273 | |||
1274 | ret = uart_add_one_port(&sci_uart_driver, &sciport->port); | ||
1275 | if (ret) | ||
1276 | return ret; | ||
1277 | |||
1278 | INIT_LIST_HEAD(&sciport->node); | ||
1279 | |||
1280 | spin_lock_irqsave(&priv->lock, flags); | ||
1281 | list_add(&sciport->node, &priv->ports); | ||
1282 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1210 | /* | 1287 | /* |
1211 | * Register a set of serial devices attached to a platform device. The | 1288 | * Register a set of serial devices attached to a platform device. The |
1212 | * list is terminated with a zero flags entry, which means we expect | 1289 | * list is terminated with a zero flags entry, which means we expect |
@@ -1216,57 +1293,34 @@ static struct uart_driver sci_uart_driver = { | |||
1216 | static int __devinit sci_probe(struct platform_device *dev) | 1293 | static int __devinit sci_probe(struct platform_device *dev) |
1217 | { | 1294 | { |
1218 | struct plat_sci_port *p = dev->dev.platform_data; | 1295 | struct plat_sci_port *p = dev->dev.platform_data; |
1296 | struct sh_sci_priv *priv; | ||
1219 | int i, ret = -EINVAL; | 1297 | int i, ret = -EINVAL; |
1220 | 1298 | ||
1221 | for (i = 0; p && p->flags != 0; p++, i++) { | 1299 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
1222 | struct sci_port *sciport = &sci_ports[i]; | 1300 | if (!priv) |
1301 | return -ENOMEM; | ||
1223 | 1302 | ||
1224 | /* Sanity check */ | 1303 | INIT_LIST_HEAD(&priv->ports); |
1225 | if (unlikely(i == SCI_NPORTS)) { | 1304 | spin_lock_init(&priv->lock); |
1226 | dev_notice(&dev->dev, "Attempting to register port " | 1305 | platform_set_drvdata(dev, priv); |
1227 | "%d when only %d are available.\n", | ||
1228 | i+1, SCI_NPORTS); | ||
1229 | dev_notice(&dev->dev, "Consider bumping " | ||
1230 | "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); | ||
1231 | break; | ||
1232 | } | ||
1233 | 1306 | ||
1234 | sciport->port.mapbase = p->mapbase; | 1307 | #ifdef CONFIG_HAVE_CLK |
1308 | priv->clk_nb.notifier_call = sci_notifier; | ||
1309 | cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1310 | #endif | ||
1235 | 1311 | ||
1236 | if (p->mapbase && !p->membase) { | 1312 | if (dev->id != -1) { |
1237 | if (p->flags & UPF_IOREMAP) { | 1313 | ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); |
1238 | p->membase = ioremap_nocache(p->mapbase, 0x40); | 1314 | if (ret) |
1239 | if (IS_ERR(p->membase)) { | 1315 | goto err_unreg; |
1240 | ret = PTR_ERR(p->membase); | 1316 | } else { |
1241 | goto err_unreg; | 1317 | for (i = 0; p && p->flags != 0; p++, i++) { |
1242 | } | 1318 | ret = sci_probe_single(dev, i, p, &sci_ports[i]); |
1243 | } else { | 1319 | if (ret) |
1244 | /* | 1320 | goto err_unreg; |
1245 | * For the simple (and majority of) cases | ||
1246 | * where we don't need to do any remapping, | ||
1247 | * just cast the cookie directly. | ||
1248 | */ | ||
1249 | p->membase = (void __iomem *)p->mapbase; | ||
1250 | } | ||
1251 | } | 1321 | } |
1252 | |||
1253 | sciport->port.membase = p->membase; | ||
1254 | |||
1255 | sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; | ||
1256 | sciport->port.flags = p->flags; | ||
1257 | sciport->port.dev = &dev->dev; | ||
1258 | |||
1259 | sciport->type = sciport->port.type = p->type; | ||
1260 | |||
1261 | memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); | ||
1262 | |||
1263 | uart_add_one_port(&sci_uart_driver, &sciport->port); | ||
1264 | } | 1322 | } |
1265 | 1323 | ||
1266 | #ifdef CONFIG_HAVE_CLK | ||
1267 | cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1268 | #endif | ||
1269 | |||
1270 | #ifdef CONFIG_SH_STANDARD_BIOS | 1324 | #ifdef CONFIG_SH_STANDARD_BIOS |
1271 | sh_bios_gdb_detach(); | 1325 | sh_bios_gdb_detach(); |
1272 | #endif | 1326 | #endif |
@@ -1274,50 +1328,36 @@ static int __devinit sci_probe(struct platform_device *dev) | |||
1274 | return 0; | 1328 | return 0; |
1275 | 1329 | ||
1276 | err_unreg: | 1330 | err_unreg: |
1277 | for (i = i - 1; i >= 0; i--) | 1331 | sci_remove(dev); |
1278 | uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); | ||
1279 | |||
1280 | return ret; | 1332 | return ret; |
1281 | } | 1333 | } |
1282 | 1334 | ||
1283 | static int __devexit sci_remove(struct platform_device *dev) | ||
1284 | { | ||
1285 | int i; | ||
1286 | |||
1287 | #ifdef CONFIG_HAVE_CLK | ||
1288 | cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); | ||
1289 | #endif | ||
1290 | |||
1291 | for (i = 0; i < SCI_NPORTS; i++) | ||
1292 | uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | static int sci_suspend(struct platform_device *dev, pm_message_t state) | 1335 | static int sci_suspend(struct platform_device *dev, pm_message_t state) |
1298 | { | 1336 | { |
1299 | int i; | 1337 | struct sh_sci_priv *priv = platform_get_drvdata(dev); |
1338 | struct sci_port *p; | ||
1339 | unsigned long flags; | ||
1300 | 1340 | ||
1301 | for (i = 0; i < SCI_NPORTS; i++) { | 1341 | spin_lock_irqsave(&priv->lock, flags); |
1302 | struct sci_port *p = &sci_ports[i]; | 1342 | list_for_each_entry(p, &priv->ports, node) |
1343 | uart_suspend_port(&sci_uart_driver, &p->port); | ||
1303 | 1344 | ||
1304 | if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) | 1345 | spin_unlock_irqrestore(&priv->lock, flags); |
1305 | uart_suspend_port(&sci_uart_driver, &p->port); | ||
1306 | } | ||
1307 | 1346 | ||
1308 | return 0; | 1347 | return 0; |
1309 | } | 1348 | } |
1310 | 1349 | ||
1311 | static int sci_resume(struct platform_device *dev) | 1350 | static int sci_resume(struct platform_device *dev) |
1312 | { | 1351 | { |
1313 | int i; | 1352 | struct sh_sci_priv *priv = platform_get_drvdata(dev); |
1353 | struct sci_port *p; | ||
1354 | unsigned long flags; | ||
1314 | 1355 | ||
1315 | for (i = 0; i < SCI_NPORTS; i++) { | 1356 | spin_lock_irqsave(&priv->lock, flags); |
1316 | struct sci_port *p = &sci_ports[i]; | 1357 | list_for_each_entry(p, &priv->ports, node) |
1358 | uart_resume_port(&sci_uart_driver, &p->port); | ||
1317 | 1359 | ||
1318 | if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) | 1360 | spin_unlock_irqrestore(&priv->lock, flags); |
1319 | uart_resume_port(&sci_uart_driver, &p->port); | ||
1320 | } | ||
1321 | 1361 | ||
1322 | return 0; | 1362 | return 0; |
1323 | } | 1363 | } |
@@ -1339,8 +1379,6 @@ static int __init sci_init(void) | |||
1339 | 1379 | ||
1340 | printk(banner); | 1380 | printk(banner); |
1341 | 1381 | ||
1342 | sci_init_ports(); | ||
1343 | |||
1344 | ret = uart_register_driver(&sci_uart_driver); | 1382 | ret = uart_register_driver(&sci_uart_driver); |
1345 | if (likely(ret == 0)) { | 1383 | if (likely(ret == 0)) { |
1346 | ret = platform_driver_register(&sci_driver); | 1384 | ret = platform_driver_register(&sci_driver); |
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index d0aa82d7fce..38072c15b84 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h | |||
@@ -91,6 +91,9 @@ | |||
91 | # define SCSPTR5 0xa4050128 | 91 | # define SCSPTR5 0xa4050128 |
92 | # define SCIF_ORER 0x0001 /* overrun error bit */ | 92 | # define SCIF_ORER 0x0001 /* overrun error bit */ |
93 | # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ | 93 | # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ |
94 | #elif defined(CONFIG_CPU_SUBTYPE_SH7724) | ||
95 | # define SCIF_ORER 0x0001 /* overrun error bit */ | ||
96 | # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ | ||
94 | #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) | 97 | #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) |
95 | # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ | 98 | # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ |
96 | # define SCIF_ORER 0x0001 /* overrun error bit */ | 99 | # define SCIF_ORER 0x0001 /* overrun error bit */ |
@@ -314,7 +317,18 @@ | |||
314 | } \ | 317 | } \ |
315 | } | 318 | } |
316 | 319 | ||
317 | #define CPU_SCIF_FNS(name, scif_offset, scif_size) \ | 320 | #ifdef CONFIG_H8300 |
321 | /* h8300 don't have SCIF */ | ||
322 | #define CPU_SCIF_FNS(name) \ | ||
323 | static inline unsigned int sci_##name##_in(struct uart_port *port) \ | ||
324 | { \ | ||
325 | return 0; \ | ||
326 | } \ | ||
327 | static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ | ||
328 | { \ | ||
329 | } | ||
330 | #else | ||
331 | #define CPU_SCIF_FNS(name, scif_offset, scif_size) \ | ||
318 | static inline unsigned int sci_##name##_in(struct uart_port *port) \ | 332 | static inline unsigned int sci_##name##_in(struct uart_port *port) \ |
319 | { \ | 333 | { \ |
320 | SCI_IN(scif_size, scif_offset); \ | 334 | SCI_IN(scif_size, scif_offset); \ |
@@ -323,6 +337,7 @@ | |||
323 | { \ | 337 | { \ |
324 | SCI_OUT(scif_size, scif_offset, value); \ | 338 | SCI_OUT(scif_size, scif_offset, value); \ |
325 | } | 339 | } |
340 | #endif | ||
326 | 341 | ||
327 | #define CPU_SCI_FNS(name, sci_offset, sci_size) \ | 342 | #define CPU_SCI_FNS(name, sci_offset, sci_size) \ |
328 | static inline unsigned int sci_##name##_in(struct uart_port* port) \ | 343 | static inline unsigned int sci_##name##_in(struct uart_port* port) \ |
@@ -360,8 +375,10 @@ | |||
360 | sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ | 375 | sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ |
361 | h8_sci_offset, h8_sci_size) \ | 376 | h8_sci_offset, h8_sci_size) \ |
362 | CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) | 377 | CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) |
363 | #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) | 378 | #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ |
364 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) | 379 | CPU_SCIF_FNS(name) |
380 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ | ||
381 | defined(CONFIG_CPU_SUBTYPE_SH7724) | ||
365 | #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ | 382 | #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ |
366 | CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) | 383 | CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) |
367 | #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ | 384 | #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ |
@@ -390,7 +407,8 @@ SCIF_FNS(SCFDR, 0x1c, 16) | |||
390 | SCIF_FNS(SCxTDR, 0x20, 8) | 407 | SCIF_FNS(SCxTDR, 0x20, 8) |
391 | SCIF_FNS(SCxRDR, 0x24, 8) | 408 | SCIF_FNS(SCxRDR, 0x24, 8) |
392 | SCIF_FNS(SCLSR, 0x24, 16) | 409 | SCIF_FNS(SCLSR, 0x24, 16) |
393 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) | 410 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ |
411 | defined(CONFIG_CPU_SUBTYPE_SH7724) | ||
394 | SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) | 412 | SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) |
395 | SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) | 413 | SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) |
396 | SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) | 414 | SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) |
@@ -604,10 +622,21 @@ static inline int sci_rxd_in(struct uart_port *port) | |||
604 | return ctrl_inb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */ | 622 | return ctrl_inb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */ |
605 | return 1; | 623 | return 1; |
606 | } | 624 | } |
625 | #elif defined(CONFIG_CPU_SUBTYPE_SH7724) | ||
626 | # define SCFSR 0x0010 | ||
627 | # define SCASSR 0x0014 | ||
628 | static inline int sci_rxd_in(struct uart_port *port) | ||
629 | { | ||
630 | if (port->type == PORT_SCIF) | ||
631 | return ctrl_inw((port->mapbase + SCFSR)) & SCIF_BRK ? 1 : 0; | ||
632 | if (port->type == PORT_SCIFA) | ||
633 | return ctrl_inw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0; | ||
634 | return 1; | ||
635 | } | ||
607 | #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) | 636 | #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) |
608 | static inline int sci_rxd_in(struct uart_port *port) | 637 | static inline int sci_rxd_in(struct uart_port *port) |
609 | { | 638 | { |
610 | return sci_in(port, SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ | 639 | return sci_in(port, SCSPTR)&0x0001 ? 1 : 0; /* SCIF */ |
611 | } | 640 | } |
612 | #elif defined(__H8300H__) || defined(__H8300S__) | 641 | #elif defined(__H8300H__) || defined(__H8300S__) |
613 | static inline int sci_rxd_in(struct uart_port *port) | 642 | static inline int sci_rxd_in(struct uart_port *port) |
@@ -757,7 +786,8 @@ static inline int sci_rxd_in(struct uart_port *port) | |||
757 | defined(CONFIG_CPU_SUBTYPE_SH7720) || \ | 786 | defined(CONFIG_CPU_SUBTYPE_SH7720) || \ |
758 | defined(CONFIG_CPU_SUBTYPE_SH7721) | 787 | defined(CONFIG_CPU_SUBTYPE_SH7721) |
759 | #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) | 788 | #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) |
760 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) | 789 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ |
790 | defined(CONFIG_CPU_SUBTYPE_SH7724) | ||
761 | static inline int scbrr_calc(struct uart_port *port, int bps, int clk) | 791 | static inline int scbrr_calc(struct uart_port *port, int bps, int clk) |
762 | { | 792 | { |
763 | if (port->type == PORT_SCIF) | 793 | if (port->type == PORT_SCIF) |
diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c new file mode 100644 index 00000000000..ac9e5d5f742 --- /dev/null +++ b/drivers/serial/timbuart.c | |||
@@ -0,0 +1,526 @@ | |||
1 | /* | ||
2 | * timbuart.c timberdale FPGA UART driver | ||
3 | * Copyright (c) 2009 Intel Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | /* Supports: | ||
20 | * Timberdale FPGA UART | ||
21 | */ | ||
22 | |||
23 | #include <linux/pci.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/serial_core.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/ioport.h> | ||
29 | |||
30 | #include "timbuart.h" | ||
31 | |||
32 | struct timbuart_port { | ||
33 | struct uart_port port; | ||
34 | struct tasklet_struct tasklet; | ||
35 | int usedma; | ||
36 | u8 last_ier; | ||
37 | struct platform_device *dev; | ||
38 | }; | ||
39 | |||
40 | static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, | ||
41 | 921600, 1843200, 3250000}; | ||
42 | |||
43 | static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier); | ||
44 | |||
45 | static irqreturn_t timbuart_handleinterrupt(int irq, void *devid); | ||
46 | |||
47 | static void timbuart_stop_rx(struct uart_port *port) | ||
48 | { | ||
49 | /* spin lock held by upper layer, disable all RX interrupts */ | ||
50 | u8 ier = ioread8(port->membase + TIMBUART_IER) & ~RXFLAGS; | ||
51 | iowrite8(ier, port->membase + TIMBUART_IER); | ||
52 | } | ||
53 | |||
54 | static void timbuart_stop_tx(struct uart_port *port) | ||
55 | { | ||
56 | /* spinlock held by upper layer, disable TX interrupt */ | ||
57 | u8 ier = ioread8(port->membase + TIMBUART_IER) & ~TXBAE; | ||
58 | iowrite8(ier, port->membase + TIMBUART_IER); | ||
59 | } | ||
60 | |||
61 | static void timbuart_start_tx(struct uart_port *port) | ||
62 | { | ||
63 | struct timbuart_port *uart = | ||
64 | container_of(port, struct timbuart_port, port); | ||
65 | |||
66 | /* do not transfer anything here -> fire off the tasklet */ | ||
67 | tasklet_schedule(&uart->tasklet); | ||
68 | } | ||
69 | |||
70 | static void timbuart_flush_buffer(struct uart_port *port) | ||
71 | { | ||
72 | u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX; | ||
73 | |||
74 | iowrite8(ctl, port->membase + TIMBUART_CTRL); | ||
75 | iowrite8(TXBF, port->membase + TIMBUART_ISR); | ||
76 | } | ||
77 | |||
78 | static void timbuart_rx_chars(struct uart_port *port) | ||
79 | { | ||
80 | struct tty_struct *tty = port->info->port.tty; | ||
81 | |||
82 | while (ioread8(port->membase + TIMBUART_ISR) & RXDP) { | ||
83 | u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); | ||
84 | port->icount.rx++; | ||
85 | tty_insert_flip_char(tty, ch, TTY_NORMAL); | ||
86 | } | ||
87 | |||
88 | spin_unlock(&port->lock); | ||
89 | tty_flip_buffer_push(port->info->port.tty); | ||
90 | spin_lock(&port->lock); | ||
91 | |||
92 | dev_dbg(port->dev, "%s - total read %d bytes\n", | ||
93 | __func__, port->icount.rx); | ||
94 | } | ||
95 | |||
96 | static void timbuart_tx_chars(struct uart_port *port) | ||
97 | { | ||
98 | struct circ_buf *xmit = &port->info->xmit; | ||
99 | |||
100 | while (!(ioread8(port->membase + TIMBUART_ISR) & TXBF) && | ||
101 | !uart_circ_empty(xmit)) { | ||
102 | iowrite8(xmit->buf[xmit->tail], | ||
103 | port->membase + TIMBUART_TXFIFO); | ||
104 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
105 | port->icount.tx++; | ||
106 | } | ||
107 | |||
108 | dev_dbg(port->dev, | ||
109 | "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", | ||
110 | __func__, | ||
111 | port->icount.tx, | ||
112 | ioread8(port->membase + TIMBUART_CTRL), | ||
113 | port->mctrl & TIOCM_RTS, | ||
114 | ioread8(port->membase + TIMBUART_BAUDRATE)); | ||
115 | } | ||
116 | |||
117 | static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier) | ||
118 | { | ||
119 | struct timbuart_port *uart = | ||
120 | container_of(port, struct timbuart_port, port); | ||
121 | struct circ_buf *xmit = &port->info->xmit; | ||
122 | |||
123 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | ||
124 | return; | ||
125 | |||
126 | if (port->x_char) | ||
127 | return; | ||
128 | |||
129 | if (isr & TXFLAGS) { | ||
130 | timbuart_tx_chars(port); | ||
131 | /* clear all TX interrupts */ | ||
132 | iowrite8(TXFLAGS, port->membase + TIMBUART_ISR); | ||
133 | |||
134 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
135 | uart_write_wakeup(port); | ||
136 | } else | ||
137 | /* Re-enable any tx interrupt */ | ||
138 | *ier |= uart->last_ier & TXFLAGS; | ||
139 | |||
140 | /* enable interrupts if there are chars in the transmit buffer, | ||
141 | * Or if we delivered some bytes and want the almost empty interrupt | ||
142 | * we wake up the upper layer later when we got the interrupt | ||
143 | * to give it some time to go out... | ||
144 | */ | ||
145 | if (!uart_circ_empty(xmit)) | ||
146 | *ier |= TXBAE; | ||
147 | |||
148 | dev_dbg(port->dev, "%s - leaving\n", __func__); | ||
149 | } | ||
150 | |||
151 | void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier) | ||
152 | { | ||
153 | if (isr & RXFLAGS) { | ||
154 | /* Some RX status is set */ | ||
155 | if (isr & RXBF) { | ||
156 | u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | | ||
157 | TIMBUART_CTRL_FLSHRX; | ||
158 | iowrite8(ctl, port->membase + TIMBUART_CTRL); | ||
159 | port->icount.overrun++; | ||
160 | } else if (isr & (RXDP)) | ||
161 | timbuart_rx_chars(port); | ||
162 | |||
163 | /* ack all RX interrupts */ | ||
164 | iowrite8(RXFLAGS, port->membase + TIMBUART_ISR); | ||
165 | } | ||
166 | |||
167 | /* always have the RX interrupts enabled */ | ||
168 | *ier |= RXBAF | RXBF | RXTT; | ||
169 | |||
170 | dev_dbg(port->dev, "%s - leaving\n", __func__); | ||
171 | } | ||
172 | |||
173 | void timbuart_tasklet(unsigned long arg) | ||
174 | { | ||
175 | struct timbuart_port *uart = (struct timbuart_port *)arg; | ||
176 | u8 isr, ier = 0; | ||
177 | |||
178 | spin_lock(&uart->port.lock); | ||
179 | |||
180 | isr = ioread8(uart->port.membase + TIMBUART_ISR); | ||
181 | dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); | ||
182 | |||
183 | if (!uart->usedma) | ||
184 | timbuart_handle_tx_port(&uart->port, isr, &ier); | ||
185 | |||
186 | timbuart_mctrl_check(&uart->port, isr, &ier); | ||
187 | |||
188 | if (!uart->usedma) | ||
189 | timbuart_handle_rx_port(&uart->port, isr, &ier); | ||
190 | |||
191 | iowrite8(ier, uart->port.membase + TIMBUART_IER); | ||
192 | |||
193 | spin_unlock(&uart->port.lock); | ||
194 | dev_dbg(uart->port.dev, "%s leaving\n", __func__); | ||
195 | } | ||
196 | |||
197 | static unsigned int timbuart_tx_empty(struct uart_port *port) | ||
198 | { | ||
199 | u8 isr = ioread8(port->membase + TIMBUART_ISR); | ||
200 | |||
201 | return (isr & TXBAE) ? TIOCSER_TEMT : 0; | ||
202 | } | ||
203 | |||
204 | static unsigned int timbuart_get_mctrl(struct uart_port *port) | ||
205 | { | ||
206 | u8 cts = ioread8(port->membase + TIMBUART_CTRL); | ||
207 | dev_dbg(port->dev, "%s - cts %x\n", __func__, cts); | ||
208 | |||
209 | if (cts & TIMBUART_CTRL_CTS) | ||
210 | return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; | ||
211 | else | ||
212 | return TIOCM_DSR | TIOCM_CAR; | ||
213 | } | ||
214 | |||
215 | static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
216 | { | ||
217 | dev_dbg(port->dev, "%s - %x\n", __func__, mctrl); | ||
218 | |||
219 | if (mctrl & TIOCM_RTS) | ||
220 | iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); | ||
221 | else | ||
222 | iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); | ||
223 | } | ||
224 | |||
225 | static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier) | ||
226 | { | ||
227 | unsigned int cts; | ||
228 | |||
229 | if (isr & CTS_DELTA) { | ||
230 | /* ack */ | ||
231 | iowrite8(CTS_DELTA, port->membase + TIMBUART_ISR); | ||
232 | cts = timbuart_get_mctrl(port); | ||
233 | uart_handle_cts_change(port, cts & TIOCM_CTS); | ||
234 | wake_up_interruptible(&port->info->delta_msr_wait); | ||
235 | } | ||
236 | |||
237 | *ier |= CTS_DELTA; | ||
238 | } | ||
239 | |||
240 | static void timbuart_enable_ms(struct uart_port *port) | ||
241 | { | ||
242 | /* N/A */ | ||
243 | } | ||
244 | |||
245 | static void timbuart_break_ctl(struct uart_port *port, int ctl) | ||
246 | { | ||
247 | /* N/A */ | ||
248 | } | ||
249 | |||
250 | static int timbuart_startup(struct uart_port *port) | ||
251 | { | ||
252 | struct timbuart_port *uart = | ||
253 | container_of(port, struct timbuart_port, port); | ||
254 | |||
255 | dev_dbg(port->dev, "%s\n", __func__); | ||
256 | |||
257 | iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL); | ||
258 | iowrite8(0xff, port->membase + TIMBUART_ISR); | ||
259 | /* Enable all but TX interrupts */ | ||
260 | iowrite8(RXBAF | RXBF | RXTT | CTS_DELTA, | ||
261 | port->membase + TIMBUART_IER); | ||
262 | |||
263 | return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED, | ||
264 | "timb-uart", uart); | ||
265 | } | ||
266 | |||
267 | static void timbuart_shutdown(struct uart_port *port) | ||
268 | { | ||
269 | struct timbuart_port *uart = | ||
270 | container_of(port, struct timbuart_port, port); | ||
271 | dev_dbg(port->dev, "%s\n", __func__); | ||
272 | free_irq(port->irq, uart); | ||
273 | iowrite8(0, port->membase + TIMBUART_IER); | ||
274 | } | ||
275 | |||
276 | static int get_bindex(int baud) | ||
277 | { | ||
278 | int i; | ||
279 | |||
280 | for (i = 0; i < ARRAY_SIZE(baudrates); i++) | ||
281 | if (baud <= baudrates[i]) | ||
282 | return i; | ||
283 | |||
284 | return -1; | ||
285 | } | ||
286 | |||
287 | static void timbuart_set_termios(struct uart_port *port, | ||
288 | struct ktermios *termios, | ||
289 | struct ktermios *old) | ||
290 | { | ||
291 | unsigned int baud; | ||
292 | short bindex; | ||
293 | unsigned long flags; | ||
294 | |||
295 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); | ||
296 | bindex = get_bindex(baud); | ||
297 | dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex); | ||
298 | |||
299 | if (bindex < 0) | ||
300 | bindex = 0; | ||
301 | baud = baudrates[bindex]; | ||
302 | |||
303 | /* The serial layer calls into this once with old = NULL when setting | ||
304 | up initially */ | ||
305 | if (old) | ||
306 | tty_termios_copy_hw(termios, old); | ||
307 | tty_termios_encode_baud_rate(termios, baud, baud); | ||
308 | |||
309 | spin_lock_irqsave(&port->lock, flags); | ||
310 | iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); | ||
311 | uart_update_timeout(port, termios->c_cflag, baud); | ||
312 | spin_unlock_irqrestore(&port->lock, flags); | ||
313 | } | ||
314 | |||
315 | static const char *timbuart_type(struct uart_port *port) | ||
316 | { | ||
317 | return port->type == PORT_UNKNOWN ? "timbuart" : NULL; | ||
318 | } | ||
319 | |||
320 | /* We do not request/release mappings of the registers here, | ||
321 | * currently it's done in the proble function. | ||
322 | */ | ||
323 | static void timbuart_release_port(struct uart_port *port) | ||
324 | { | ||
325 | struct platform_device *pdev = to_platform_device(port->dev); | ||
326 | int size = | ||
327 | resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
328 | |||
329 | if (port->flags & UPF_IOREMAP) { | ||
330 | iounmap(port->membase); | ||
331 | port->membase = NULL; | ||
332 | } | ||
333 | |||
334 | release_mem_region(port->mapbase, size); | ||
335 | } | ||
336 | |||
337 | static int timbuart_request_port(struct uart_port *port) | ||
338 | { | ||
339 | struct platform_device *pdev = to_platform_device(port->dev); | ||
340 | int size = | ||
341 | resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
342 | |||
343 | if (!request_mem_region(port->mapbase, size, "timb-uart")) | ||
344 | return -EBUSY; | ||
345 | |||
346 | if (port->flags & UPF_IOREMAP) { | ||
347 | port->membase = ioremap(port->mapbase, size); | ||
348 | if (port->membase == NULL) { | ||
349 | release_mem_region(port->mapbase, size); | ||
350 | return -ENOMEM; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static irqreturn_t timbuart_handleinterrupt(int irq, void *devid) | ||
358 | { | ||
359 | struct timbuart_port *uart = (struct timbuart_port *)devid; | ||
360 | |||
361 | if (ioread8(uart->port.membase + TIMBUART_IPR)) { | ||
362 | uart->last_ier = ioread8(uart->port.membase + TIMBUART_IER); | ||
363 | |||
364 | /* disable interrupts, the tasklet enables them again */ | ||
365 | iowrite8(0, uart->port.membase + TIMBUART_IER); | ||
366 | |||
367 | /* fire off bottom half */ | ||
368 | tasklet_schedule(&uart->tasklet); | ||
369 | |||
370 | return IRQ_HANDLED; | ||
371 | } else | ||
372 | return IRQ_NONE; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Configure/autoconfigure the port. | ||
377 | */ | ||
378 | static void timbuart_config_port(struct uart_port *port, int flags) | ||
379 | { | ||
380 | if (flags & UART_CONFIG_TYPE) { | ||
381 | port->type = PORT_TIMBUART; | ||
382 | timbuart_request_port(port); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | static int timbuart_verify_port(struct uart_port *port, | ||
387 | struct serial_struct *ser) | ||
388 | { | ||
389 | /* we don't want the core code to modify any port params */ | ||
390 | return -EINVAL; | ||
391 | } | ||
392 | |||
393 | static struct uart_ops timbuart_ops = { | ||
394 | .tx_empty = timbuart_tx_empty, | ||
395 | .set_mctrl = timbuart_set_mctrl, | ||
396 | .get_mctrl = timbuart_get_mctrl, | ||
397 | .stop_tx = timbuart_stop_tx, | ||
398 | .start_tx = timbuart_start_tx, | ||
399 | .flush_buffer = timbuart_flush_buffer, | ||
400 | .stop_rx = timbuart_stop_rx, | ||
401 | .enable_ms = timbuart_enable_ms, | ||
402 | .break_ctl = timbuart_break_ctl, | ||
403 | .startup = timbuart_startup, | ||
404 | .shutdown = timbuart_shutdown, | ||
405 | .set_termios = timbuart_set_termios, | ||
406 | .type = timbuart_type, | ||
407 | .release_port = timbuart_release_port, | ||
408 | .request_port = timbuart_request_port, | ||
409 | .config_port = timbuart_config_port, | ||
410 | .verify_port = timbuart_verify_port | ||
411 | }; | ||
412 | |||
413 | static struct uart_driver timbuart_driver = { | ||
414 | .owner = THIS_MODULE, | ||
415 | .driver_name = "timberdale_uart", | ||
416 | .dev_name = "ttyTU", | ||
417 | .major = TIMBUART_MAJOR, | ||
418 | .minor = TIMBUART_MINOR, | ||
419 | .nr = 1 | ||
420 | }; | ||
421 | |||
422 | static int timbuart_probe(struct platform_device *dev) | ||
423 | { | ||
424 | int err; | ||
425 | struct timbuart_port *uart; | ||
426 | struct resource *iomem; | ||
427 | |||
428 | dev_dbg(&dev->dev, "%s\n", __func__); | ||
429 | |||
430 | uart = kzalloc(sizeof(*uart), GFP_KERNEL); | ||
431 | if (!uart) { | ||
432 | err = -EINVAL; | ||
433 | goto err_mem; | ||
434 | } | ||
435 | |||
436 | uart->usedma = 0; | ||
437 | |||
438 | uart->port.uartclk = 3250000 * 16; | ||
439 | uart->port.fifosize = TIMBUART_FIFO_SIZE; | ||
440 | uart->port.regshift = 2; | ||
441 | uart->port.iotype = UPIO_MEM; | ||
442 | uart->port.ops = &timbuart_ops; | ||
443 | uart->port.irq = 0; | ||
444 | uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; | ||
445 | uart->port.line = 0; | ||
446 | uart->port.dev = &dev->dev; | ||
447 | |||
448 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
449 | if (!iomem) { | ||
450 | err = -ENOMEM; | ||
451 | goto err_register; | ||
452 | } | ||
453 | uart->port.mapbase = iomem->start; | ||
454 | uart->port.membase = NULL; | ||
455 | |||
456 | uart->port.irq = platform_get_irq(dev, 0); | ||
457 | if (uart->port.irq < 0) { | ||
458 | err = -EINVAL; | ||
459 | goto err_register; | ||
460 | } | ||
461 | |||
462 | tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); | ||
463 | |||
464 | err = uart_register_driver(&timbuart_driver); | ||
465 | if (err) | ||
466 | goto err_register; | ||
467 | |||
468 | err = uart_add_one_port(&timbuart_driver, &uart->port); | ||
469 | if (err) | ||
470 | goto err_add_port; | ||
471 | |||
472 | platform_set_drvdata(dev, uart); | ||
473 | |||
474 | return 0; | ||
475 | |||
476 | err_add_port: | ||
477 | uart_unregister_driver(&timbuart_driver); | ||
478 | err_register: | ||
479 | kfree(uart); | ||
480 | err_mem: | ||
481 | printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n", | ||
482 | err); | ||
483 | |||
484 | return err; | ||
485 | } | ||
486 | |||
487 | static int timbuart_remove(struct platform_device *dev) | ||
488 | { | ||
489 | struct timbuart_port *uart = platform_get_drvdata(dev); | ||
490 | |||
491 | tasklet_kill(&uart->tasklet); | ||
492 | uart_remove_one_port(&timbuart_driver, &uart->port); | ||
493 | uart_unregister_driver(&timbuart_driver); | ||
494 | kfree(uart); | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static struct platform_driver timbuart_platform_driver = { | ||
500 | .driver = { | ||
501 | .name = "timb-uart", | ||
502 | .owner = THIS_MODULE, | ||
503 | }, | ||
504 | .probe = timbuart_probe, | ||
505 | .remove = timbuart_remove, | ||
506 | }; | ||
507 | |||
508 | /*--------------------------------------------------------------------------*/ | ||
509 | |||
510 | static int __init timbuart_init(void) | ||
511 | { | ||
512 | return platform_driver_register(&timbuart_platform_driver); | ||
513 | } | ||
514 | |||
515 | static void __exit timbuart_exit(void) | ||
516 | { | ||
517 | platform_driver_unregister(&timbuart_platform_driver); | ||
518 | } | ||
519 | |||
520 | module_init(timbuart_init); | ||
521 | module_exit(timbuart_exit); | ||
522 | |||
523 | MODULE_DESCRIPTION("Timberdale UART driver"); | ||
524 | MODULE_LICENSE("GPL v2"); | ||
525 | MODULE_ALIAS("platform:timb-uart"); | ||
526 | |||
diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h new file mode 100644 index 00000000000..7e566766bc4 --- /dev/null +++ b/drivers/serial/timbuart.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * timbuart.c timberdale FPGA GPIO driver | ||
3 | * Copyright (c) 2009 Intel Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | /* Supports: | ||
20 | * Timberdale FPGA UART | ||
21 | */ | ||
22 | |||
23 | #ifndef _TIMBUART_H | ||
24 | #define _TIMBUART_H | ||
25 | |||
26 | #define TIMBUART_FIFO_SIZE 2048 | ||
27 | |||
28 | #define TIMBUART_RXFIFO 0x08 | ||
29 | #define TIMBUART_TXFIFO 0x0c | ||
30 | #define TIMBUART_IER 0x10 | ||
31 | #define TIMBUART_IPR 0x14 | ||
32 | #define TIMBUART_ISR 0x18 | ||
33 | #define TIMBUART_CTRL 0x1c | ||
34 | #define TIMBUART_BAUDRATE 0x20 | ||
35 | |||
36 | #define TIMBUART_CTRL_RTS 0x01 | ||
37 | #define TIMBUART_CTRL_CTS 0x02 | ||
38 | #define TIMBUART_CTRL_FLSHTX 0x40 | ||
39 | #define TIMBUART_CTRL_FLSHRX 0x80 | ||
40 | |||
41 | #define TXBF 0x01 | ||
42 | #define TXBAE 0x02 | ||
43 | #define CTS_DELTA 0x04 | ||
44 | #define RXDP 0x08 | ||
45 | #define RXBAF 0x10 | ||
46 | #define RXBF 0x20 | ||
47 | #define RXTT 0x40 | ||
48 | #define RXBNAE 0x80 | ||
49 | #define TXBE 0x100 | ||
50 | |||
51 | #define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE) | ||
52 | #define TXFLAGS (TXBF | TXBAE) | ||
53 | |||
54 | #define TIMBUART_MAJOR 204 | ||
55 | #define TIMBUART_MINOR 192 | ||
56 | |||
57 | #endif /* _TIMBUART_H */ | ||
58 | |||