diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-12-18 17:15:30 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-12-18 17:15:30 -0500 |
commit | fdb0a1a67e131f07a308730c80d07e330211d2e0 (patch) | |
tree | 4fbf35055fc965737c1ffdbcfe98d7ea8335f940 /drivers/serial | |
parent | fc0b7a20368193e1f7cf1376624eed419b9c33e6 (diff) | |
parent | 7bb56d01f111890414fbe35412698485b68ed468 (diff) |
Merge branch 'next-merged' of git://aeryn.fluff.org.uk/bjdooks/linux into devel
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/Kconfig | 25 | ||||
-rw-r--r-- | drivers/serial/Makefile | 2 | ||||
-rw-r--r-- | drivers/serial/s3c24a0.c | 118 | ||||
-rw-r--r-- | drivers/serial/s3c6400.c | 151 | ||||
-rw-r--r-- | drivers/serial/samsung.c | 184 | ||||
-rw-r--r-- | drivers/serial/samsung.h | 9 |
6 files changed, 451 insertions, 38 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 579d63a81aa2..b695ab3142d8 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -447,7 +447,7 @@ config SERIAL_CLPS711X_CONSOLE | |||
447 | 447 | ||
448 | config SERIAL_SAMSUNG | 448 | config SERIAL_SAMSUNG |
449 | tristate "Samsung SoC serial support" | 449 | tristate "Samsung SoC serial support" |
450 | depends on ARM && PLAT_S3C24XX | 450 | depends on ARM && PLAT_S3C |
451 | select SERIAL_CORE | 451 | select SERIAL_CORE |
452 | help | 452 | help |
453 | Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, | 453 | Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, |
@@ -455,6 +455,16 @@ config SERIAL_SAMSUNG | |||
455 | provide all of these ports, depending on how the serial port | 455 | provide all of these ports, depending on how the serial port |
456 | pins are configured. | 456 | pins are configured. |
457 | 457 | ||
458 | config SERIAL_SAMSUNG_UARTS | ||
459 | int | ||
460 | depends on SERIAL_SAMSUNG | ||
461 | default 2 if ARCH_S3C2400 | ||
462 | default 4 if ARCH_S3C64XX || CPU_S3C2443 | ||
463 | default 3 | ||
464 | help | ||
465 | Select the number of available UART ports for the Samsung S3C | ||
466 | serial driver | ||
467 | |||
458 | config SERIAL_SAMSUNG_DEBUG | 468 | config SERIAL_SAMSUNG_DEBUG |
459 | bool "Samsung SoC serial debug" | 469 | bool "Samsung SoC serial debug" |
460 | depends on SERIAL_SAMSUNG && DEBUG_LL | 470 | depends on SERIAL_SAMSUNG && DEBUG_LL |
@@ -508,7 +518,20 @@ config SERIAL_S3C2440 | |||
508 | help | 518 | help |
509 | Serial port support for the Samsung S3C2440 and S3C2442 SoC | 519 | Serial port support for the Samsung S3C2440 and S3C2442 SoC |
510 | 520 | ||
521 | config SERIAL_S3C24A0 | ||
522 | tristate "Samsung S3C24A0 Serial port support" | ||
523 | depends on SERIAL_SAMSUNG && CPU_S3C24A0 | ||
524 | default y if CPU_S3C24A0 | ||
525 | help | ||
526 | Serial port support for the Samsung S3C24A0 SoC | ||
511 | 527 | ||
528 | config SERIAL_S3C6400 | ||
529 | tristate "Samsung S3C6400/S3C6410 Serial port support" | ||
530 | depends on SERIAL_SAMSUNG && (CPU_S3C600 || CPU_S3C6410) | ||
531 | default y | ||
532 | help | ||
533 | Serial port support for the Samsung S3C6400 and S3C6410 | ||
534 | SoCs | ||
512 | 535 | ||
513 | config SERIAL_DZ | 536 | config SERIAL_DZ |
514 | bool "DECstation DZ serial driver" | 537 | bool "DECstation DZ serial driver" |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 0c17c8ddb19d..dfe775ac45b2 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
@@ -41,6 +41,8 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o | |||
41 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o | 41 | obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o |
42 | obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o | 42 | obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o |
43 | obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o | 43 | obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o |
44 | obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o | ||
45 | obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o | ||
44 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o | 46 | obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o |
45 | obj-$(CONFIG_SERIAL_MUX) += mux.o | 47 | obj-$(CONFIG_SERIAL_MUX) += mux.o |
46 | obj-$(CONFIG_SERIAL_68328) += 68328serial.o | 48 | obj-$(CONFIG_SERIAL_68328) += 68328serial.o |
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c new file mode 100644 index 000000000000..ebf2fd3c8f7d --- /dev/null +++ b/drivers/serial/s3c24a0.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* linux/drivers/serial/s3c24a0.c | ||
2 | * | ||
3 | * Driver for Samsung S3C24A0 SoC onboard UARTs. | ||
4 | * | ||
5 | * Based on drivers/serial/s3c2410.c | ||
6 | * | ||
7 | * Author: Sandeep Patil <sandeep.patil@azingo.com> | ||
8 | * | ||
9 | * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics | ||
10 | * http://armlinux.simtec.co.uk/ | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/serial_core.h> | ||
22 | #include <linux/serial.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/irq.h> | ||
25 | |||
26 | #include <mach/hardware.h> | ||
27 | |||
28 | #include <plat/regs-serial.h> | ||
29 | #include <mach/regs-gpio.h> | ||
30 | |||
31 | #include "samsung.h" | ||
32 | |||
33 | static int s3c24a0_serial_setsource(struct uart_port *port, | ||
34 | struct s3c24xx_uart_clksrc *clk) | ||
35 | { | ||
36 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | ||
37 | |||
38 | if (strcmp(clk->name, "uclk") == 0) | ||
39 | ucon |= S3C2410_UCON_UCLK; | ||
40 | else | ||
41 | ucon &= ~S3C2410_UCON_UCLK; | ||
42 | |||
43 | wr_regl(port, S3C2410_UCON, ucon); | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int s3c24a0_serial_getsource(struct uart_port *port, | ||
48 | struct s3c24xx_uart_clksrc *clk) | ||
49 | { | ||
50 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | ||
51 | |||
52 | clk->divisor = 1; | ||
53 | clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk"; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int s3c24a0_serial_resetport(struct uart_port *port, | ||
59 | struct s3c2410_uartcfg *cfg) | ||
60 | { | ||
61 | dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n", | ||
62 | port, port->mapbase, cfg); | ||
63 | |||
64 | wr_regl(port, S3C2410_UCON, cfg->ucon); | ||
65 | wr_regl(port, S3C2410_ULCON, cfg->ulcon); | ||
66 | |||
67 | /* reset both fifos */ | ||
68 | |||
69 | wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); | ||
70 | wr_regl(port, S3C2410_UFCON, cfg->ufcon); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static struct s3c24xx_uart_info s3c24a0_uart_inf = { | ||
76 | .name = "Samsung S3C24A0 UART", | ||
77 | .type = PORT_S3C2410, | ||
78 | .fifosize = 16, | ||
79 | .rx_fifomask = S3C24A0_UFSTAT_RXMASK, | ||
80 | .rx_fifoshift = S3C24A0_UFSTAT_RXSHIFT, | ||
81 | .rx_fifofull = S3C24A0_UFSTAT_RXFULL, | ||
82 | .tx_fifofull = S3C24A0_UFSTAT_TXFULL, | ||
83 | .tx_fifomask = S3C24A0_UFSTAT_TXMASK, | ||
84 | .tx_fifoshift = S3C24A0_UFSTAT_TXSHIFT, | ||
85 | .get_clksrc = s3c24a0_serial_getsource, | ||
86 | .set_clksrc = s3c24a0_serial_setsource, | ||
87 | .reset_port = s3c24a0_serial_resetport, | ||
88 | }; | ||
89 | |||
90 | static int s3c24a0_serial_probe(struct platform_device *dev) | ||
91 | { | ||
92 | return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf); | ||
93 | } | ||
94 | |||
95 | static struct platform_driver s3c24a0_serial_drv = { | ||
96 | .probe = s3c24a0_serial_probe, | ||
97 | .remove = s3c24xx_serial_remove, | ||
98 | .driver = { | ||
99 | .name = "s3c24a0-uart", | ||
100 | .owner = THIS_MODULE, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | s3c24xx_console_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf); | ||
105 | |||
106 | static int __init s3c24a0_serial_init(void) | ||
107 | { | ||
108 | return s3c24xx_serial_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf); | ||
109 | } | ||
110 | |||
111 | static void __exit s3c24a0_serial_exit(void) | ||
112 | { | ||
113 | platform_driver_unregister(&s3c24a0_serial_drv); | ||
114 | } | ||
115 | |||
116 | module_init(s3c24a0_serial_init); | ||
117 | module_exit(s3c24a0_serial_exit); | ||
118 | |||
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c new file mode 100644 index 000000000000..06936d13393f --- /dev/null +++ b/drivers/serial/s3c6400.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* linux/drivers/serial/s3c6400.c | ||
2 | * | ||
3 | * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs. | ||
4 | * | ||
5 | * Copyright 2008 Openmoko, Inc. | ||
6 | * Copyright 2008 Simtec Electronics | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * http://armlinux.simtec.co.uk/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/serial_core.h> | ||
21 | #include <linux/serial.h> | ||
22 | |||
23 | #include <asm/irq.h> | ||
24 | #include <mach/hardware.h> | ||
25 | |||
26 | #include <plat/regs-serial.h> | ||
27 | |||
28 | #include "samsung.h" | ||
29 | |||
30 | static int s3c6400_serial_setsource(struct uart_port *port, | ||
31 | struct s3c24xx_uart_clksrc *clk) | ||
32 | { | ||
33 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | ||
34 | |||
35 | if (strcmp(clk->name, "uclk0") == 0) { | ||
36 | ucon &= ~S3C6400_UCON_CLKMASK; | ||
37 | ucon |= S3C6400_UCON_UCLK0; | ||
38 | } else if (strcmp(clk->name, "uclk1") == 0) | ||
39 | ucon |= S3C6400_UCON_UCLK1; | ||
40 | else if (strcmp(clk->name, "pclk") == 0) { | ||
41 | /* See notes about transitioning from UCLK to PCLK */ | ||
42 | ucon &= ~S3C6400_UCON_UCLK0; | ||
43 | } else { | ||
44 | printk(KERN_ERR "unknown clock source %s\n", clk->name); | ||
45 | return -EINVAL; | ||
46 | } | ||
47 | |||
48 | wr_regl(port, S3C2410_UCON, ucon); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | |||
53 | static int s3c6400_serial_getsource(struct uart_port *port, | ||
54 | struct s3c24xx_uart_clksrc *clk) | ||
55 | { | ||
56 | u32 ucon = rd_regl(port, S3C2410_UCON); | ||
57 | |||
58 | clk->divisor = 1; | ||
59 | |||
60 | switch (ucon & S3C6400_UCON_CLKMASK) { | ||
61 | case S3C6400_UCON_UCLK0: | ||
62 | clk->name = "uclk0"; | ||
63 | break; | ||
64 | |||
65 | case S3C6400_UCON_UCLK1: | ||
66 | clk->name = "uclk1"; | ||
67 | break; | ||
68 | |||
69 | case S3C6400_UCON_PCLK: | ||
70 | case S3C6400_UCON_PCLK2: | ||
71 | clk->name = "pclk"; | ||
72 | break; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int s3c6400_serial_resetport(struct uart_port *port, | ||
79 | struct s3c2410_uartcfg *cfg) | ||
80 | { | ||
81 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | ||
82 | |||
83 | dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n", | ||
84 | port, port->mapbase, cfg); | ||
85 | |||
86 | /* ensure we don't change the clock settings... */ | ||
87 | |||
88 | ucon &= S3C6400_UCON_CLKMASK; | ||
89 | |||
90 | wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); | ||
91 | wr_regl(port, S3C2410_ULCON, cfg->ulcon); | ||
92 | |||
93 | /* reset both fifos */ | ||
94 | |||
95 | wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); | ||
96 | wr_regl(port, S3C2410_UFCON, cfg->ufcon); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static struct s3c24xx_uart_info s3c6400_uart_inf = { | ||
102 | .name = "Samsung S3C6400 UART", | ||
103 | .type = PORT_S3C6400, | ||
104 | .fifosize = 64, | ||
105 | .rx_fifomask = S3C2440_UFSTAT_RXMASK, | ||
106 | .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, | ||
107 | .rx_fifofull = S3C2440_UFSTAT_RXFULL, | ||
108 | .tx_fifofull = S3C2440_UFSTAT_TXFULL, | ||
109 | .tx_fifomask = S3C2440_UFSTAT_TXMASK, | ||
110 | .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, | ||
111 | .get_clksrc = s3c6400_serial_getsource, | ||
112 | .set_clksrc = s3c6400_serial_setsource, | ||
113 | .reset_port = s3c6400_serial_resetport, | ||
114 | }; | ||
115 | |||
116 | /* device management */ | ||
117 | |||
118 | static int s3c6400_serial_probe(struct platform_device *dev) | ||
119 | { | ||
120 | dbg("s3c6400_serial_probe: dev=%p\n", dev); | ||
121 | return s3c24xx_serial_probe(dev, &s3c6400_uart_inf); | ||
122 | } | ||
123 | |||
124 | static struct platform_driver s3c6400_serial_drv = { | ||
125 | .probe = s3c6400_serial_probe, | ||
126 | .remove = s3c24xx_serial_remove, | ||
127 | .driver = { | ||
128 | .name = "s3c6400-uart", | ||
129 | .owner = THIS_MODULE, | ||
130 | }, | ||
131 | }; | ||
132 | |||
133 | s3c24xx_console_init(&s3c6400_serial_drv, &s3c6400_uart_inf); | ||
134 | |||
135 | static int __init s3c6400_serial_init(void) | ||
136 | { | ||
137 | return s3c24xx_serial_init(&s3c6400_serial_drv, &s3c6400_uart_inf); | ||
138 | } | ||
139 | |||
140 | static void __exit s3c6400_serial_exit(void) | ||
141 | { | ||
142 | platform_driver_unregister(&s3c6400_serial_drv); | ||
143 | } | ||
144 | |||
145 | module_init(s3c6400_serial_init); | ||
146 | module_exit(s3c6400_serial_exit); | ||
147 | |||
148 | MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver"); | ||
149 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
150 | MODULE_LICENSE("GPL v2"); | ||
151 | MODULE_ALIAS("platform:s3c6400-uart"); | ||
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index 1e219d3d0352..41ac94872b8d 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c | |||
@@ -42,13 +42,14 @@ | |||
42 | #include <linux/serial.h> | 42 | #include <linux/serial.h> |
43 | #include <linux/delay.h> | 43 | #include <linux/delay.h> |
44 | #include <linux/clk.h> | 44 | #include <linux/clk.h> |
45 | #include <linux/cpufreq.h> | ||
45 | 46 | ||
46 | #include <asm/irq.h> | 47 | #include <asm/irq.h> |
47 | 48 | ||
48 | #include <mach/hardware.h> | 49 | #include <mach/hardware.h> |
50 | #include <mach/map.h> | ||
49 | 51 | ||
50 | #include <plat/regs-serial.h> | 52 | #include <plat/regs-serial.h> |
51 | #include <mach/regs-gpio.h> | ||
52 | 53 | ||
53 | #include "samsung.h" | 54 | #include "samsung.h" |
54 | 55 | ||
@@ -58,19 +59,6 @@ | |||
58 | #define S3C24XX_SERIAL_MAJOR 204 | 59 | #define S3C24XX_SERIAL_MAJOR 204 |
59 | #define S3C24XX_SERIAL_MINOR 64 | 60 | #define S3C24XX_SERIAL_MINOR 64 |
60 | 61 | ||
61 | /* we can support 3 uarts, but not always use them */ | ||
62 | |||
63 | #ifdef CONFIG_CPU_S3C2400 | ||
64 | #define NR_PORTS (2) | ||
65 | #else | ||
66 | #define NR_PORTS (3) | ||
67 | #endif | ||
68 | |||
69 | /* port irq numbers */ | ||
70 | |||
71 | #define TX_IRQ(port) ((port)->irq + 1) | ||
72 | #define RX_IRQ(port) ((port)->irq) | ||
73 | |||
74 | /* macros to change one thing to another */ | 62 | /* macros to change one thing to another */ |
75 | 63 | ||
76 | #define tx_enabled(port) ((port)->unused[0]) | 64 | #define tx_enabled(port) ((port)->unused[0]) |
@@ -136,8 +124,10 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port) | |||
136 | 124 | ||
137 | static void s3c24xx_serial_stop_tx(struct uart_port *port) | 125 | static void s3c24xx_serial_stop_tx(struct uart_port *port) |
138 | { | 126 | { |
127 | struct s3c24xx_uart_port *ourport = to_ourport(port); | ||
128 | |||
139 | if (tx_enabled(port)) { | 129 | if (tx_enabled(port)) { |
140 | disable_irq(TX_IRQ(port)); | 130 | disable_irq(ourport->tx_irq); |
141 | tx_enabled(port) = 0; | 131 | tx_enabled(port) = 0; |
142 | if (port->flags & UPF_CONS_FLOW) | 132 | if (port->flags & UPF_CONS_FLOW) |
143 | s3c24xx_serial_rx_enable(port); | 133 | s3c24xx_serial_rx_enable(port); |
@@ -146,11 +136,13 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) | |||
146 | 136 | ||
147 | static void s3c24xx_serial_start_tx(struct uart_port *port) | 137 | static void s3c24xx_serial_start_tx(struct uart_port *port) |
148 | { | 138 | { |
139 | struct s3c24xx_uart_port *ourport = to_ourport(port); | ||
140 | |||
149 | if (!tx_enabled(port)) { | 141 | if (!tx_enabled(port)) { |
150 | if (port->flags & UPF_CONS_FLOW) | 142 | if (port->flags & UPF_CONS_FLOW) |
151 | s3c24xx_serial_rx_disable(port); | 143 | s3c24xx_serial_rx_disable(port); |
152 | 144 | ||
153 | enable_irq(TX_IRQ(port)); | 145 | enable_irq(ourport->tx_irq); |
154 | tx_enabled(port) = 1; | 146 | tx_enabled(port) = 1; |
155 | } | 147 | } |
156 | } | 148 | } |
@@ -158,9 +150,11 @@ static void s3c24xx_serial_start_tx(struct uart_port *port) | |||
158 | 150 | ||
159 | static void s3c24xx_serial_stop_rx(struct uart_port *port) | 151 | static void s3c24xx_serial_stop_rx(struct uart_port *port) |
160 | { | 152 | { |
153 | struct s3c24xx_uart_port *ourport = to_ourport(port); | ||
154 | |||
161 | if (rx_enabled(port)) { | 155 | if (rx_enabled(port)) { |
162 | dbg("s3c24xx_serial_stop_rx: port=%p\n", port); | 156 | dbg("s3c24xx_serial_stop_rx: port=%p\n", port); |
163 | disable_irq(RX_IRQ(port)); | 157 | disable_irq(ourport->rx_irq); |
164 | rx_enabled(port) = 0; | 158 | rx_enabled(port) = 0; |
165 | } | 159 | } |
166 | } | 160 | } |
@@ -384,13 +378,13 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) | |||
384 | struct s3c24xx_uart_port *ourport = to_ourport(port); | 378 | struct s3c24xx_uart_port *ourport = to_ourport(port); |
385 | 379 | ||
386 | if (ourport->tx_claimed) { | 380 | if (ourport->tx_claimed) { |
387 | free_irq(TX_IRQ(port), ourport); | 381 | free_irq(ourport->tx_irq, ourport); |
388 | tx_enabled(port) = 0; | 382 | tx_enabled(port) = 0; |
389 | ourport->tx_claimed = 0; | 383 | ourport->tx_claimed = 0; |
390 | } | 384 | } |
391 | 385 | ||
392 | if (ourport->rx_claimed) { | 386 | if (ourport->rx_claimed) { |
393 | free_irq(RX_IRQ(port), ourport); | 387 | free_irq(ourport->rx_irq, ourport); |
394 | ourport->rx_claimed = 0; | 388 | ourport->rx_claimed = 0; |
395 | rx_enabled(port) = 0; | 389 | rx_enabled(port) = 0; |
396 | } | 390 | } |
@@ -407,12 +401,11 @@ static int s3c24xx_serial_startup(struct uart_port *port) | |||
407 | 401 | ||
408 | rx_enabled(port) = 1; | 402 | rx_enabled(port) = 1; |
409 | 403 | ||
410 | ret = request_irq(RX_IRQ(port), | 404 | ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, |
411 | s3c24xx_serial_rx_chars, 0, | ||
412 | s3c24xx_serial_portname(port), ourport); | 405 | s3c24xx_serial_portname(port), ourport); |
413 | 406 | ||
414 | if (ret != 0) { | 407 | if (ret != 0) { |
415 | printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port)); | 408 | printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq); |
416 | return ret; | 409 | return ret; |
417 | } | 410 | } |
418 | 411 | ||
@@ -422,12 +415,11 @@ static int s3c24xx_serial_startup(struct uart_port *port) | |||
422 | 415 | ||
423 | tx_enabled(port) = 1; | 416 | tx_enabled(port) = 1; |
424 | 417 | ||
425 | ret = request_irq(TX_IRQ(port), | 418 | ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, |
426 | s3c24xx_serial_tx_chars, 0, | ||
427 | s3c24xx_serial_portname(port), ourport); | 419 | s3c24xx_serial_portname(port), ourport); |
428 | 420 | ||
429 | if (ret) { | 421 | if (ret) { |
430 | printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port)); | 422 | printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq); |
431 | goto err; | 423 | goto err; |
432 | } | 424 | } |
433 | 425 | ||
@@ -452,6 +444,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, | |||
452 | { | 444 | { |
453 | struct s3c24xx_uart_port *ourport = to_ourport(port); | 445 | struct s3c24xx_uart_port *ourport = to_ourport(port); |
454 | 446 | ||
447 | ourport->pm_level = level; | ||
448 | |||
455 | switch (level) { | 449 | switch (level) { |
456 | case 3: | 450 | case 3: |
457 | if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) | 451 | if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) |
@@ -661,6 +655,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, | |||
661 | 655 | ||
662 | ourport->clksrc = clksrc; | 656 | ourport->clksrc = clksrc; |
663 | ourport->baudclk = clk; | 657 | ourport->baudclk = clk; |
658 | ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; | ||
664 | } | 659 | } |
665 | 660 | ||
666 | switch (termios->c_cflag & CSIZE) { | 661 | switch (termios->c_cflag & CSIZE) { |
@@ -752,6 +747,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port) | |||
752 | return "S3C2440"; | 747 | return "S3C2440"; |
753 | case PORT_S3C2412: | 748 | case PORT_S3C2412: |
754 | return "S3C2412"; | 749 | return "S3C2412"; |
750 | case PORT_S3C6400: | ||
751 | return "S3C6400/10"; | ||
755 | default: | 752 | default: |
756 | return NULL; | 753 | return NULL; |
757 | } | 754 | } |
@@ -827,14 +824,14 @@ static struct uart_ops s3c24xx_serial_ops = { | |||
827 | static struct uart_driver s3c24xx_uart_drv = { | 824 | static struct uart_driver s3c24xx_uart_drv = { |
828 | .owner = THIS_MODULE, | 825 | .owner = THIS_MODULE, |
829 | .dev_name = "s3c2410_serial", | 826 | .dev_name = "s3c2410_serial", |
830 | .nr = 3, | 827 | .nr = CONFIG_SERIAL_SAMSUNG_UARTS, |
831 | .cons = S3C24XX_SERIAL_CONSOLE, | 828 | .cons = S3C24XX_SERIAL_CONSOLE, |
832 | .driver_name = S3C24XX_SERIAL_NAME, | 829 | .driver_name = S3C24XX_SERIAL_NAME, |
833 | .major = S3C24XX_SERIAL_MAJOR, | 830 | .major = S3C24XX_SERIAL_MAJOR, |
834 | .minor = S3C24XX_SERIAL_MINOR, | 831 | .minor = S3C24XX_SERIAL_MINOR, |
835 | }; | 832 | }; |
836 | 833 | ||
837 | static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = { | 834 | static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { |
838 | [0] = { | 835 | [0] = { |
839 | .port = { | 836 | .port = { |
840 | .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), | 837 | .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), |
@@ -859,7 +856,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = { | |||
859 | .line = 1, | 856 | .line = 1, |
860 | } | 857 | } |
861 | }, | 858 | }, |
862 | #if NR_PORTS > 2 | 859 | #if CONFIG_SERIAL_SAMSUNG_UARTS > 2 |
863 | 860 | ||
864 | [2] = { | 861 | [2] = { |
865 | .port = { | 862 | .port = { |
@@ -872,6 +869,20 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = { | |||
872 | .flags = UPF_BOOT_AUTOCONF, | 869 | .flags = UPF_BOOT_AUTOCONF, |
873 | .line = 2, | 870 | .line = 2, |
874 | } | 871 | } |
872 | }, | ||
873 | #endif | ||
874 | #if CONFIG_SERIAL_SAMSUNG_UARTS > 3 | ||
875 | [3] = { | ||
876 | .port = { | ||
877 | .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock), | ||
878 | .iotype = UPIO_MEM, | ||
879 | .irq = IRQ_S3CUART_RX3, | ||
880 | .uartclk = 0, | ||
881 | .fifosize = 16, | ||
882 | .ops = &s3c24xx_serial_ops, | ||
883 | .flags = UPF_BOOT_AUTOCONF, | ||
884 | .line = 3, | ||
885 | } | ||
875 | } | 886 | } |
876 | #endif | 887 | #endif |
877 | }; | 888 | }; |
@@ -890,6 +901,89 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port, | |||
890 | return (info->reset_port)(port, cfg); | 901 | return (info->reset_port)(port, cfg); |
891 | } | 902 | } |
892 | 903 | ||
904 | |||
905 | #ifdef CONFIG_CPU_FREQ | ||
906 | |||
907 | static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, | ||
908 | unsigned long val, void *data) | ||
909 | { | ||
910 | struct s3c24xx_uart_port *port; | ||
911 | struct uart_port *uport; | ||
912 | |||
913 | port = container_of(nb, struct s3c24xx_uart_port, freq_transition); | ||
914 | uport = &port->port; | ||
915 | |||
916 | /* check to see if port is enabled */ | ||
917 | |||
918 | if (port->pm_level != 0) | ||
919 | return 0; | ||
920 | |||
921 | /* try and work out if the baudrate is changing, we can detect | ||
922 | * a change in rate, but we do not have support for detecting | ||
923 | * a disturbance in the clock-rate over the change. | ||
924 | */ | ||
925 | |||
926 | if (IS_ERR(port->clk)) | ||
927 | goto exit; | ||
928 | |||
929 | if (port->baudclk_rate == clk_get_rate(port->clk)) | ||
930 | goto exit; | ||
931 | |||
932 | if (val == CPUFREQ_PRECHANGE) { | ||
933 | /* we should really shut the port down whilst the | ||
934 | * frequency change is in progress. */ | ||
935 | |||
936 | } else if (val == CPUFREQ_POSTCHANGE) { | ||
937 | struct ktermios *termios; | ||
938 | struct tty_struct *tty; | ||
939 | |||
940 | if (uport->info == NULL) | ||
941 | goto exit; | ||
942 | |||
943 | tty = uport->info->port.tty; | ||
944 | |||
945 | if (tty == NULL) | ||
946 | goto exit; | ||
947 | |||
948 | termios = tty->termios; | ||
949 | |||
950 | if (termios == NULL) { | ||
951 | printk(KERN_WARNING "%s: no termios?\n", __func__); | ||
952 | goto exit; | ||
953 | } | ||
954 | |||
955 | s3c24xx_serial_set_termios(uport, termios, NULL); | ||
956 | } | ||
957 | |||
958 | exit: | ||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) | ||
963 | { | ||
964 | port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition; | ||
965 | |||
966 | return cpufreq_register_notifier(&port->freq_transition, | ||
967 | CPUFREQ_TRANSITION_NOTIFIER); | ||
968 | } | ||
969 | |||
970 | static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) | ||
971 | { | ||
972 | cpufreq_unregister_notifier(&port->freq_transition, | ||
973 | CPUFREQ_TRANSITION_NOTIFIER); | ||
974 | } | ||
975 | |||
976 | #else | ||
977 | static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) | ||
978 | { | ||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) | ||
983 | { | ||
984 | } | ||
985 | #endif | ||
986 | |||
893 | /* s3c24xx_serial_init_port | 987 | /* s3c24xx_serial_init_port |
894 | * | 988 | * |
895 | * initialise a single serial port from the platform device given | 989 | * initialise a single serial port from the platform device given |
@@ -914,8 +1008,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, | |||
914 | if (port->mapbase != 0) | 1008 | if (port->mapbase != 0) |
915 | return 0; | 1009 | return 0; |
916 | 1010 | ||
917 | if (cfg->hwport > 3) | 1011 | if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) { |
918 | return -EINVAL; | 1012 | printk(KERN_ERR "%s: port %d bigger than %d\n", __func__, |
1013 | cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS); | ||
1014 | return -ERANGE; | ||
1015 | } | ||
919 | 1016 | ||
920 | /* setup info for port */ | 1017 | /* setup info for port */ |
921 | port->dev = &platdev->dev; | 1018 | port->dev = &platdev->dev; |
@@ -943,18 +1040,26 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, | |||
943 | 1040 | ||
944 | dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); | 1041 | dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); |
945 | 1042 | ||
946 | port->mapbase = res->start; | 1043 | port->mapbase = res->start; |
947 | port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART); | 1044 | port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000); |
948 | ret = platform_get_irq(platdev, 0); | 1045 | ret = platform_get_irq(platdev, 0); |
949 | if (ret < 0) | 1046 | if (ret < 0) |
950 | port->irq = 0; | 1047 | port->irq = 0; |
951 | else | 1048 | else { |
952 | port->irq = ret; | 1049 | port->irq = ret; |
1050 | ourport->rx_irq = ret; | ||
1051 | ourport->tx_irq = ret + 1; | ||
1052 | } | ||
1053 | |||
1054 | ret = platform_get_irq(platdev, 1); | ||
1055 | if (ret > 0) | ||
1056 | ourport->tx_irq = ret; | ||
953 | 1057 | ||
954 | ourport->clk = clk_get(&platdev->dev, "uart"); | 1058 | ourport->clk = clk_get(&platdev->dev, "uart"); |
955 | 1059 | ||
956 | dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n", | 1060 | dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n", |
957 | port->mapbase, port->membase, port->irq, port->uartclk); | 1061 | port->mapbase, port->membase, port->irq, |
1062 | ourport->rx_irq, ourport->tx_irq, port->uartclk); | ||
958 | 1063 | ||
959 | /* reset the fifos (and setup the uart) */ | 1064 | /* reset the fifos (and setup the uart) */ |
960 | s3c24xx_serial_resetport(port, cfg); | 1065 | s3c24xx_serial_resetport(port, cfg); |
@@ -1002,6 +1107,10 @@ int s3c24xx_serial_probe(struct platform_device *dev, | |||
1002 | if (ret < 0) | 1107 | if (ret < 0) |
1003 | printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); | 1108 | printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); |
1004 | 1109 | ||
1110 | ret = s3c24xx_serial_cpufreq_register(ourport); | ||
1111 | if (ret < 0) | ||
1112 | dev_err(&dev->dev, "failed to add cpufreq notifier\n"); | ||
1113 | |||
1005 | return 0; | 1114 | return 0; |
1006 | 1115 | ||
1007 | probe_err: | 1116 | probe_err: |
@@ -1015,6 +1124,7 @@ int s3c24xx_serial_remove(struct platform_device *dev) | |||
1015 | struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); | 1124 | struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); |
1016 | 1125 | ||
1017 | if (port) { | 1126 | if (port) { |
1127 | s3c24xx_serial_cpufreq_deregister(to_ourport(port)); | ||
1018 | device_remove_file(&dev->dev, &dev_attr_clock_source); | 1128 | device_remove_file(&dev->dev, &dev_attr_clock_source); |
1019 | uart_remove_one_port(&s3c24xx_uart_drv, port); | 1129 | uart_remove_one_port(&s3c24xx_uart_drv, port); |
1020 | } | 1130 | } |
@@ -1219,7 +1329,7 @@ static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info) | |||
1219 | 1329 | ||
1220 | platdev_ptr = s3c24xx_uart_devs; | 1330 | platdev_ptr = s3c24xx_uart_devs; |
1221 | 1331 | ||
1222 | for (i = 0; i < NR_PORTS; i++, ptr++, platdev_ptr++) { | 1332 | for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) { |
1223 | s3c24xx_serial_init_port(ptr, info, *platdev_ptr); | 1333 | s3c24xx_serial_init_port(ptr, info, *platdev_ptr); |
1224 | } | 1334 | } |
1225 | 1335 | ||
@@ -1240,7 +1350,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options) | |||
1240 | 1350 | ||
1241 | /* is this a valid port */ | 1351 | /* is this a valid port */ |
1242 | 1352 | ||
1243 | if (co->index == -1 || co->index >= NR_PORTS) | 1353 | if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS) |
1244 | co->index = 0; | 1354 | co->index = 0; |
1245 | 1355 | ||
1246 | port = &s3c24xx_serial_ports[co->index].port; | 1356 | port = &s3c24xx_serial_ports[co->index].port; |
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h index 5c92ebbe7d9e..571d6b90d206 100644 --- a/drivers/serial/samsung.h +++ b/drivers/serial/samsung.h | |||
@@ -33,12 +33,21 @@ struct s3c24xx_uart_info { | |||
33 | struct s3c24xx_uart_port { | 33 | struct s3c24xx_uart_port { |
34 | unsigned char rx_claimed; | 34 | unsigned char rx_claimed; |
35 | unsigned char tx_claimed; | 35 | unsigned char tx_claimed; |
36 | unsigned int pm_level; | ||
37 | unsigned long baudclk_rate; | ||
38 | |||
39 | unsigned int rx_irq; | ||
40 | unsigned int tx_irq; | ||
36 | 41 | ||
37 | struct s3c24xx_uart_info *info; | 42 | struct s3c24xx_uart_info *info; |
38 | struct s3c24xx_uart_clksrc *clksrc; | 43 | struct s3c24xx_uart_clksrc *clksrc; |
39 | struct clk *clk; | 44 | struct clk *clk; |
40 | struct clk *baudclk; | 45 | struct clk *baudclk; |
41 | struct uart_port port; | 46 | struct uart_port port; |
47 | |||
48 | #ifdef CONFIG_CPU_FREQ | ||
49 | struct notifier_block freq_transition; | ||
50 | #endif | ||
42 | }; | 51 | }; |
43 | 52 | ||
44 | /* conversion functions */ | 53 | /* conversion functions */ |