Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SERIAL] amba-pl010: allow platforms to specify modem control method

The amba-pl010 hardware does not provide RTS and DTR control lines; it
is expected that these will be implemented using GPIO. Allow platforms
to supply a function to implement manipulation of modem control lines.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Russell King and committed by
Russell King
fbb18a27 335bd9df

+119 -93
+46
arch/arm/mach-integrator/core.c
··· 15 15 #include <linux/interrupt.h> 16 16 #include <linux/sched.h> 17 17 #include <linux/smp.h> 18 + #include <linux/termios.h> 18 19 #include <linux/amba/bus.h> 20 + #include <linux/amba/serial.h> 19 21 20 22 #include <asm/hardware.h> 21 23 #include <asm/irq.h> ··· 29 27 #include <asm/mach/time.h> 30 28 31 29 #include "common.h" 30 + 31 + static struct amba_pl010_data integrator_uart_data; 32 32 33 33 static struct amba_device rtc_device = { 34 34 .dev = { ··· 48 44 static struct amba_device uart0_device = { 49 45 .dev = { 50 46 .bus_id = "mb:16", 47 + .platform_data = &integrator_uart_data, 51 48 }, 52 49 .res = { 53 50 .start = INTEGRATOR_UART0_BASE, ··· 62 57 static struct amba_device uart1_device = { 63 58 .dev = { 64 59 .bus_id = "mb:17", 60 + .platform_data = &integrator_uart_data, 65 61 }, 66 62 .res = { 67 63 .start = INTEGRATOR_UART1_BASE, ··· 120 114 } 121 115 122 116 arch_initcall(integrator_init); 117 + 118 + /* 119 + * On the Integrator platform, the port RTS and DTR are provided by 120 + * bits in the following SC_CTRLS register bits: 121 + * RTS DTR 122 + * UART0 7 6 123 + * UART1 5 4 124 + */ 125 + #define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) 126 + #define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) 127 + 128 + static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl) 129 + { 130 + unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask; 131 + 132 + if (dev == &uart0_device) { 133 + rts_mask = 1 << 4; 134 + dtr_mask = 1 << 5; 135 + } else { 136 + rts_mask = 1 << 6; 137 + dtr_mask = 1 << 7; 138 + } 139 + 140 + if (mctrl & TIOCM_RTS) 141 + ctrlc |= rts_mask; 142 + else 143 + ctrls |= rts_mask; 144 + 145 + if (mctrl & TIOCM_DTR) 146 + ctrlc |= dtr_mask; 147 + else 148 + ctrls |= dtr_mask; 149 + 150 + __raw_writel(ctrls, SC_CTRLS); 151 + __raw_writel(ctrlc, SC_CTRLC); 152 + } 153 + 154 + static struct amba_pl010_data integrator_uart_data = { 155 + .set_mctrl = integrator_uart_set_mctrl, 156 + }; 123 157 124 158 #define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET 125 159
+67 -93
drivers/serial/amba-pl010.c
··· 51 51 #include <linux/amba/serial.h> 52 52 53 53 #include <asm/io.h> 54 - #include <asm/irq.h> 55 - #include <asm/hardware.h> 56 54 57 55 #define UART_NR 2 58 56 ··· 63 65 #define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) 64 66 #define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) 65 67 66 - #define UART_DUMMY_RSR_RX /*256*/0 68 + #define UART_DUMMY_RSR_RX 256 67 69 #define UART_PORT_SIZE 64 68 - 69 - /* 70 - * On the Integrator platform, the port RTS and DTR are provided by 71 - * bits in the following SC_CTRLS register bits: 72 - * RTS DTR 73 - * UART0 7 6 74 - * UART1 5 4 75 - */ 76 - #define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) 77 - #define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) 78 70 79 71 /* 80 72 * We wrap our port structure around the generic uart_port. 81 73 */ 82 74 struct uart_amba_port { 83 75 struct uart_port port; 84 - unsigned int dtr_mask; 85 - unsigned int rts_mask; 76 + struct amba_device *dev; 77 + struct amba_pl010_data *data; 86 78 unsigned int old_status; 87 79 }; 88 80 ··· 288 300 static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) 289 301 { 290 302 struct uart_amba_port *uap = (struct uart_amba_port *)port; 291 - unsigned int ctrls = 0, ctrlc = 0; 292 303 293 - if (mctrl & TIOCM_RTS) 294 - ctrlc |= uap->rts_mask; 295 - else 296 - ctrls |= uap->rts_mask; 297 - 298 - if (mctrl & TIOCM_DTR) 299 - ctrlc |= uap->dtr_mask; 300 - else 301 - ctrls |= uap->dtr_mask; 302 - 303 - __raw_writel(ctrls, SC_CTRLS); 304 - __raw_writel(ctrlc, SC_CTRLC); 304 + if (uap->data) 305 + uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl); 305 306 } 306 307 307 308 static void pl010_break_ctl(struct uart_port *port, int break_state) ··· 516 539 .verify_port = pl010_verify_port, 517 540 }; 518 541 519 - static struct uart_amba_port amba_ports[UART_NR] = { 520 - { 521 - .port = { 522 - .membase = (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE), 523 - .mapbase = INTEGRATOR_UART0_BASE, 524 - .iotype = UPIO_MEM, 525 - .irq = IRQ_UARTINT0, 526 - .uartclk = 14745600, 527 - .fifosize = 16, 528 - .ops = &amba_pl010_pops, 529 - .flags = UPF_BOOT_AUTOCONF, 530 - .line = 0, 531 - }, 532 - .dtr_mask = 1 << 5, 533 - .rts_mask = 1 << 4, 534 - }, 535 - { 536 - .port = { 537 - .membase = (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE), 538 - .mapbase = INTEGRATOR_UART1_BASE, 539 - .iotype = UPIO_MEM, 540 - .irq = IRQ_UARTINT1, 541 - .uartclk = 14745600, 542 - .fifosize = 16, 543 - .ops = &amba_pl010_pops, 544 - .flags = UPF_BOOT_AUTOCONF, 545 - .line = 1, 546 - }, 547 - .dtr_mask = 1 << 7, 548 - .rts_mask = 1 << 6, 549 - } 550 - }; 542 + static struct uart_amba_port *amba_ports[UART_NR]; 551 543 552 544 #ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE 553 545 ··· 534 588 static void 535 589 pl010_console_write(struct console *co, const char *s, unsigned int count) 536 590 { 537 - struct uart_port *port = &amba_ports[co->index].port; 591 + struct uart_port *port = &amba_ports[co->index]->port; 538 592 unsigned int status, old_cr; 539 593 540 594 /* ··· 597 651 */ 598 652 if (co->index >= UART_NR) 599 653 co->index = 0; 600 - port = &amba_ports[co->index].port; 654 + port = &amba_ports[co->index]->port; 601 655 602 656 if (options) 603 657 uart_parse_options(options, &baud, &parity, &bits, &flow); ··· 618 672 .data = &amba_reg, 619 673 }; 620 674 621 - static int __init amba_console_init(void) 622 - { 623 - /* 624 - * All port initializations are done statically 625 - */ 626 - register_console(&amba_console); 627 - return 0; 628 - } 629 - console_initcall(amba_console_init); 630 - 631 - static int __init amba_late_console_init(void) 632 - { 633 - if (!(amba_console.flags & CON_ENABLED)) 634 - register_console(&amba_console); 635 - return 0; 636 - } 637 - late_initcall(amba_late_console_init); 638 - 639 675 #define AMBA_CONSOLE &amba_console 640 676 #else 641 677 #define AMBA_CONSOLE NULL ··· 635 707 636 708 static int pl010_probe(struct amba_device *dev, void *id) 637 709 { 638 - int i; 710 + struct uart_amba_port *port; 711 + void __iomem *base; 712 + int i, ret; 639 713 640 - for (i = 0; i < UART_NR; i++) { 641 - if (amba_ports[i].port.mapbase != dev->res.start) 642 - continue; 714 + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) 715 + if (amba_ports[i] == NULL) 716 + break; 643 717 644 - amba_ports[i].port.dev = &dev->dev; 645 - uart_add_one_port(&amba_reg, &amba_ports[i].port); 646 - amba_set_drvdata(dev, &amba_ports[i]); 647 - break; 718 + if (i == ARRAY_SIZE(amba_ports)) { 719 + ret = -EBUSY; 720 + goto out; 648 721 } 649 722 650 - return 0; 723 + port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); 724 + if (!port) { 725 + ret = -ENOMEM; 726 + goto out; 727 + } 728 + 729 + base = ioremap(dev->res.start, PAGE_SIZE); 730 + if (!base) { 731 + ret = -ENOMEM; 732 + goto free; 733 + } 734 + 735 + port->port.dev = &dev->dev; 736 + port->port.mapbase = dev->res.start; 737 + port->port.membase = base; 738 + port->port.iotype = UPIO_MEM; 739 + port->port.irq = dev->irq[0]; 740 + port->port.uartclk = 14745600; 741 + port->port.fifosize = 16; 742 + port->port.ops = &amba_pl010_pops; 743 + port->port.flags = UPF_BOOT_AUTOCONF; 744 + port->port.line = i; 745 + port->dev = dev; 746 + port->data = dev->dev.platform_data; 747 + 748 + amba_ports[i] = port; 749 + 750 + amba_set_drvdata(dev, port); 751 + ret = uart_add_one_port(&amba_reg, &port->port); 752 + if (ret) { 753 + amba_set_drvdata(dev, NULL); 754 + amba_ports[i] = NULL; 755 + iounmap(base); 756 + free: 757 + kfree(port); 758 + } 759 + 760 + out: 761 + return ret; 651 762 } 652 763 653 764 static int pl010_remove(struct amba_device *dev) 654 765 { 655 - struct uart_amba_port *uap = amba_get_drvdata(dev); 656 - 657 - if (uap) 658 - uart_remove_one_port(&amba_reg, &uap->port); 766 + struct uart_amba_port *port = amba_get_drvdata(dev); 767 + int i; 659 768 660 769 amba_set_drvdata(dev, NULL); 770 + 771 + uart_remove_one_port(&amba_reg, &port->port); 772 + 773 + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) 774 + if (amba_ports[i] == port) 775 + amba_ports[i] = NULL; 776 + 777 + iounmap(port->port.membase); 778 + kfree(port); 661 779 662 780 return 0; 663 781 }
+6
include/linux/amba/serial.h
··· 158 158 #define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE) 159 159 #define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS) 160 160 161 + #ifndef __ASSEMBLY__ 162 + struct amba_pl010_data { 163 + void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl); 164 + }; 165 + #endif 166 + 161 167 #endif