aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-03-26 17:13:39 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-03-26 17:13:39 -0500
commitfbb18a277a6f192404aa20ece49529acb1e1e76d (patch)
tree2ae2b039d05ce15ad6e0f7209877aaf918f8f24a
parent335bd9dff31d042b773591933d3ee5bd62d5ea27 (diff)
[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>
-rw-r--r--arch/arm/mach-integrator/core.c46
-rw-r--r--drivers/serial/amba-pl010.c160
-rw-r--r--include/linux/amba/serial.h6
3 files changed, 119 insertions, 93 deletions
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 20071a2767cc..576a5e979c00 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -15,7 +15,9 @@
15#include <linux/interrupt.h> 15#include <linux/interrupt.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/smp.h> 17#include <linux/smp.h>
18#include <linux/termios.h>
18#include <linux/amba/bus.h> 19#include <linux/amba/bus.h>
20#include <linux/amba/serial.h>
19 21
20#include <asm/hardware.h> 22#include <asm/hardware.h>
21#include <asm/irq.h> 23#include <asm/irq.h>
@@ -28,6 +30,8 @@
28 30
29#include "common.h" 31#include "common.h"
30 32
33static struct amba_pl010_data integrator_uart_data;
34
31static struct amba_device rtc_device = { 35static struct amba_device rtc_device = {
32 .dev = { 36 .dev = {
33 .bus_id = "mb:15", 37 .bus_id = "mb:15",
@@ -44,6 +48,7 @@ static struct amba_device rtc_device = {
44static struct amba_device uart0_device = { 48static struct amba_device uart0_device = {
45 .dev = { 49 .dev = {
46 .bus_id = "mb:16", 50 .bus_id = "mb:16",
51 .platform_data = &integrator_uart_data,
47 }, 52 },
48 .res = { 53 .res = {
49 .start = INTEGRATOR_UART0_BASE, 54 .start = INTEGRATOR_UART0_BASE,
@@ -57,6 +62,7 @@ static struct amba_device uart0_device = {
57static struct amba_device uart1_device = { 62static struct amba_device uart1_device = {
58 .dev = { 63 .dev = {
59 .bus_id = "mb:17", 64 .bus_id = "mb:17",
65 .platform_data = &integrator_uart_data,
60 }, 66 },
61 .res = { 67 .res = {
62 .start = INTEGRATOR_UART1_BASE, 68 .start = INTEGRATOR_UART1_BASE,
@@ -115,6 +121,46 @@ static int __init integrator_init(void)
115 121
116arch_initcall(integrator_init); 122arch_initcall(integrator_init);
117 123
124/*
125 * On the Integrator platform, the port RTS and DTR are provided by
126 * bits in the following SC_CTRLS register bits:
127 * RTS DTR
128 * UART0 7 6
129 * UART1 5 4
130 */
131#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
132#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
133
134static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
135{
136 unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
137
138 if (dev == &uart0_device) {
139 rts_mask = 1 << 4;
140 dtr_mask = 1 << 5;
141 } else {
142 rts_mask = 1 << 6;
143 dtr_mask = 1 << 7;
144 }
145
146 if (mctrl & TIOCM_RTS)
147 ctrlc |= rts_mask;
148 else
149 ctrls |= rts_mask;
150
151 if (mctrl & TIOCM_DTR)
152 ctrlc |= dtr_mask;
153 else
154 ctrls |= dtr_mask;
155
156 __raw_writel(ctrls, SC_CTRLS);
157 __raw_writel(ctrlc, SC_CTRLC);
158}
159
160static struct amba_pl010_data integrator_uart_data = {
161 .set_mctrl = integrator_uart_set_mctrl,
162};
163
118#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET 164#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
119 165
120static DEFINE_SPINLOCK(cm_lock); 166static DEFINE_SPINLOCK(cm_lock);
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 127d6cd5de7f..1631414000a2 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -51,8 +51,6 @@
51#include <linux/amba/serial.h> 51#include <linux/amba/serial.h>
52 52
53#include <asm/io.h> 53#include <asm/io.h>
54#include <asm/irq.h>
55#include <asm/hardware.h>
56 54
57#define UART_NR 2 55#define UART_NR 2
58 56
@@ -65,26 +63,16 @@
65#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) 63#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0)
66#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) 64#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0)
67 65
68#define UART_DUMMY_RSR_RX /*256*/0 66#define UART_DUMMY_RSR_RX 256
69#define UART_PORT_SIZE 64 67#define UART_PORT_SIZE 64
70 68
71/* 69/*
72 * On the Integrator platform, the port RTS and DTR are provided by
73 * bits in the following SC_CTRLS register bits:
74 * RTS DTR
75 * UART0 7 6
76 * UART1 5 4
77 */
78#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
79#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
80
81/*
82 * We wrap our port structure around the generic uart_port. 70 * We wrap our port structure around the generic uart_port.
83 */ 71 */
84struct uart_amba_port { 72struct uart_amba_port {
85 struct uart_port port; 73 struct uart_port port;
86 unsigned int dtr_mask; 74 struct amba_device *dev;
87 unsigned int rts_mask; 75 struct amba_pl010_data *data;
88 unsigned int old_status; 76 unsigned int old_status;
89}; 77};
90 78
@@ -300,20 +288,9 @@ static unsigned int pl010_get_mctrl(struct uart_port *port)
300static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) 288static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
301{ 289{
302 struct uart_amba_port *uap = (struct uart_amba_port *)port; 290 struct uart_amba_port *uap = (struct uart_amba_port *)port;
303 unsigned int ctrls = 0, ctrlc = 0;
304
305 if (mctrl & TIOCM_RTS)
306 ctrlc |= uap->rts_mask;
307 else
308 ctrls |= uap->rts_mask;
309 291
310 if (mctrl & TIOCM_DTR) 292 if (uap->data)
311 ctrlc |= uap->dtr_mask; 293 uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
312 else
313 ctrls |= uap->dtr_mask;
314
315 __raw_writel(ctrls, SC_CTRLS);
316 __raw_writel(ctrlc, SC_CTRLC);
317} 294}
318 295
319static void pl010_break_ctl(struct uart_port *port, int break_state) 296static void pl010_break_ctl(struct uart_port *port, int break_state)
@@ -539,38 +516,7 @@ static struct uart_ops amba_pl010_pops = {
539 .verify_port = pl010_verify_port, 516 .verify_port = pl010_verify_port,
540}; 517};
541 518
542static struct uart_amba_port amba_ports[UART_NR] = { 519static struct uart_amba_port *amba_ports[UART_NR];
543 {
544 .port = {
545 .membase = (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
546 .mapbase = INTEGRATOR_UART0_BASE,
547 .iotype = UPIO_MEM,
548 .irq = IRQ_UARTINT0,
549 .uartclk = 14745600,
550 .fifosize = 16,
551 .ops = &amba_pl010_pops,
552 .flags = UPF_BOOT_AUTOCONF,
553 .line = 0,
554 },
555 .dtr_mask = 1 << 5,
556 .rts_mask = 1 << 4,
557 },
558 {
559 .port = {
560 .membase = (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
561 .mapbase = INTEGRATOR_UART1_BASE,
562 .iotype = UPIO_MEM,
563 .irq = IRQ_UARTINT1,
564 .uartclk = 14745600,
565 .fifosize = 16,
566 .ops = &amba_pl010_pops,
567 .flags = UPF_BOOT_AUTOCONF,
568 .line = 1,
569 },
570 .dtr_mask = 1 << 7,
571 .rts_mask = 1 << 6,
572 }
573};
574 520
575#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE 521#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
576 522
@@ -588,7 +534,7 @@ static void pl010_console_putchar(struct uart_port *port, int ch)
588static void 534static void
589pl010_console_write(struct console *co, const char *s, unsigned int count) 535pl010_console_write(struct console *co, const char *s, unsigned int count)
590{ 536{
591 struct uart_port *port = &amba_ports[co->index].port; 537 struct uart_port *port = &amba_ports[co->index]->port;
592 unsigned int status, old_cr; 538 unsigned int status, old_cr;
593 539
594 /* 540 /*
@@ -651,7 +597,7 @@ static int __init pl010_console_setup(struct console *co, char *options)
651 */ 597 */
652 if (co->index >= UART_NR) 598 if (co->index >= UART_NR)
653 co->index = 0; 599 co->index = 0;
654 port = &amba_ports[co->index].port; 600 port = &amba_ports[co->index]->port;
655 601
656 if (options) 602 if (options)
657 uart_parse_options(options, &baud, &parity, &bits, &flow); 603 uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -672,24 +618,6 @@ static struct console amba_console = {
672 .data = &amba_reg, 618 .data = &amba_reg,
673}; 619};
674 620
675static int __init amba_console_init(void)
676{
677 /*
678 * All port initializations are done statically
679 */
680 register_console(&amba_console);
681 return 0;
682}
683console_initcall(amba_console_init);
684
685static int __init amba_late_console_init(void)
686{
687 if (!(amba_console.flags & CON_ENABLED))
688 register_console(&amba_console);
689 return 0;
690}
691late_initcall(amba_late_console_init);
692
693#define AMBA_CONSOLE &amba_console 621#define AMBA_CONSOLE &amba_console
694#else 622#else
695#define AMBA_CONSOLE NULL 623#define AMBA_CONSOLE NULL
@@ -707,30 +635,76 @@ static struct uart_driver amba_reg = {
707 635
708static int pl010_probe(struct amba_device *dev, void *id) 636static int pl010_probe(struct amba_device *dev, void *id)
709{ 637{
710 int i; 638 struct uart_amba_port *port;
639 void __iomem *base;
640 int i, ret;
711 641
712 for (i = 0; i < UART_NR; i++) { 642 for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
713 if (amba_ports[i].port.mapbase != dev->res.start) 643 if (amba_ports[i] == NULL)
714 continue; 644 break;
715 645
716 amba_ports[i].port.dev = &dev->dev; 646 if (i == ARRAY_SIZE(amba_ports)) {
717 uart_add_one_port(&amba_reg, &amba_ports[i].port); 647 ret = -EBUSY;
718 amba_set_drvdata(dev, &amba_ports[i]); 648 goto out;
719 break;
720 } 649 }
721 650
722 return 0; 651 port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
652 if (!port) {
653 ret = -ENOMEM;
654 goto out;
655 }
656
657 base = ioremap(dev->res.start, PAGE_SIZE);
658 if (!base) {
659 ret = -ENOMEM;
660 goto free;
661 }
662
663 port->port.dev = &dev->dev;
664 port->port.mapbase = dev->res.start;
665 port->port.membase = base;
666 port->port.iotype = UPIO_MEM;
667 port->port.irq = dev->irq[0];
668 port->port.uartclk = 14745600;
669 port->port.fifosize = 16;
670 port->port.ops = &amba_pl010_pops;
671 port->port.flags = UPF_BOOT_AUTOCONF;
672 port->port.line = i;
673 port->dev = dev;
674 port->data = dev->dev.platform_data;
675
676 amba_ports[i] = port;
677
678 amba_set_drvdata(dev, port);
679 ret = uart_add_one_port(&amba_reg, &port->port);
680 if (ret) {
681 amba_set_drvdata(dev, NULL);
682 amba_ports[i] = NULL;
683 iounmap(base);
684 free:
685 kfree(port);
686 }
687
688 out:
689 return ret;
723} 690}
724 691
725static int pl010_remove(struct amba_device *dev) 692static int pl010_remove(struct amba_device *dev)
726{ 693{
727 struct uart_amba_port *uap = amba_get_drvdata(dev); 694 struct uart_amba_port *port = amba_get_drvdata(dev);
728 695 int i;
729 if (uap)
730 uart_remove_one_port(&amba_reg, &uap->port);
731 696
732 amba_set_drvdata(dev, NULL); 697 amba_set_drvdata(dev, NULL);
733 698
699 uart_remove_one_port(&amba_reg, &port->port);
700
701 for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
702 if (amba_ports[i] == port)
703 amba_ports[i] = NULL;
704
705 iounmap(port->port.membase);
706 kfree(port);
707
734 return 0; 708 return 0;
735} 709}
736 710
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index dc726ffccebd..48ee32a18ac5 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -158,4 +158,10 @@
158#define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE) 158#define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE)
159#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS) 159#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS)
160 160
161#ifndef __ASSEMBLY__
162struct amba_pl010_data {
163 void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl);
164};
165#endif
166
161#endif 167#endif